; QDOS  High-performance operating system for the 8086  version 0.11
;	by Tim Paterson


; Interrupt Entry Points:

; INTBASE:	ABORT
; INTBASE+4:	COMMAND
; INTBASE+8:	BASE EXIT ADDRESS
; INTBASE+C:	CONTROL-C ABORT
; INTBASE+10H:	FATAL ERROR ABORT
; INTBASE+14H:	BIOS DISK READ
; INTBASE+18H:	BIOS DISK WRITE
; INTBASE+40H:	Long jump to CALL entry point


MAXCALL:EQU	36
MAXCOM:	EQU	40
ESCCH:	EQU	1BH
INTBASE:EQU	80H
INTTAB:	EQU	20H
ENTRYPOINTSEG:	EQU	0CH
ENTRYPOINT:	EQU	INTBASE+40H
CONTC:	EQU	INTTAB+3
EXIT:	EQU	INTBASE+8
LONGJUMP:EQU	0EAH
LONGCALL:EQU	9AH
MAXDIF:	EQU	0FFFH
SAVEXIT:EQU	10

; Field definition for FCBs

	ORG	0
	DS	12		;Drive code and name
EXTENT:	DS	4
ENTPOS:	DS	2		;Position of entry in directory
DRVBP:	DS	2		;BP for SEARCH FIRST and SEARCH NEXT
FIRCLUS:DS	2		;First cluster of file
LSTCLUS:DS	2		;Last cluster accessed
FILSIZ:	DS	2		;Size of file in records
CLUSPOS:DS	2		;Position of last cluster accessed
DIRTYFIL:DS	1		;File has been written to if <>0
SIZCHG:	DS	1		;Directory needs update if <>0
	ORG	32
NR:	DS	1		;Next record
RR:	DS	3		;Random record


; Description of 16-byte directory entry (same as returned by SEARCH FIRST
; and SEARCH NEXT, functions 17 and 18).
;
; Location	bytes	Description
;
;    0		11	File name and extension ( 0E5H if empty)
;   11		 2	First allocation unit ( < 4080 )
;   13		 3	File size, in bytes (LSB first, 24 bits max.)


; Field definition for Drive Parameter Block

	ORG	0
DRVNUM:	DS	1		;Drive number
SECSIZ:	DS	1		;Size of physical sector in records
CLUSMSK:DS	1		;Records/cluster - 1
CLUSSHFT:DS	1		;Log2 of records/cluster
FIRFAT:	DS	2		;Starting record of FATs
FATSIZ:	DS	1		;Number of records occupied by FAT
FATCNT:	DS	1		;Number of FATs for this drive
FIRDIR:	DS	2		;Starting record of directory
DIRSIZ:	DS	1		;Number of records occupied by directory
FIRREC:	DS	2		;First record of first cluster
MAXCLUS:DS	2		;Number of clusters on drive + 1
DIRTYFAT:DS	1		;-1=FAT has been changed
FAT:	DS	2		;Start of FAT

DPBSIZ:	EQU	$


; BIOS entry point defintions

BIOSSEG:	EQU	40H
		ORG	0
		DS	3
BIOSSTAT:	DS	3
BIOSIN:		DS	3
BIOSOUT:	DS	3
BIOSPRINT:	DS	3
BIOSAUXIN:	DS	3
BIOSAUXOUT:	DS	3
BIOSREAD:	DS	3
BIOSWRITE:	DS	3
BIOSFLUSH:	DS	3


; Start of code

	ORG	0
	PUT	100H

	JMP	DOSINIT

ESCTAB:	
	DB	"SC"	;Copy one char
	DB	"VN"	;Skip one char
	DB	"TA"	;Copy to char
	DB	"WB"	;Skip to char
	DB	"UH"	;Copy line
	DB	"HH"	;Kill line (no change in template)
	DB	"RM"	;Reedit line (new template)
	DB	"DD"	;Backspace
	DB	"P@"	;Enter insert mode
	DB	"QL"	;Exit insert mode
	DB	ESCCH,ESCCH	;Escape character
	DB	ESCCH,ESCCH	;End of table

ESCTABLEN:EQU	$-ESCTAB

HEADER:	DB	13,10,"86-DOS version 0.11"
	DB	13,10
	DB	"Copyright 1980 Seattle Computer Products, Inc.",13,10,"$"

DOSINIT:
	DI
	UP
	MOV	AX,CS
	MOV	ES,AX
	LODB
	CBW
	MOV	CX,AX
	SEG	CS
	MOV	[NUMDRV],AL
	MOV	DI,AX
	SHL	DI
	MOV	AH,DPBSIZ
	MUL	AX,AH
	MOV	BX,DRVTAB
	ADD	DI,BX
	ADD	AX,DI
	MOV	BP,AX
	SEG	CS
	MOV	[FATBASE],AX
PERDEV:
	SEG	CS
	MOV	[BX],DI
	INC	BX
	INC	BX
	MOV	AL,CH
	STOB			;DRVNUM
	LODW			;Pointer to DPT
	PUSH	SI
	MOV	SI,AX
	MOVB			;SECSIZ
	LODB
	DEC	AL
	STOB			;CLUSMSK
	CBW
FIGSHFT:
	INC	AH
	SAR	AL
	JNZ	FIGSHFT
	MOV	AL,AH
	STOB			;CLUSSHFT
	LODW
	STOW			;FIRFAT (= number of reserved records)
	MOV	DX,AX
	LODB
	STOB			;FATSIZ
	MOV	AH,AL
	PUSH	AX
	LODB
	STOB			;FATCNT
	MUL	AX,AH
	ADD	AX,DX
	STOW			;FIRDIR
	MOV	DX,AX
	LODB
	STOB			;DIRSIZ
	CBW
	ADD	AX,DX
	STOW			;FIRREC
	POP	DX
	LODW
	INC	AX
	STOW			;MAXCLUS
	XOR	AL,AL
	STOB
	POP	SI		;Restore pointer to init. table
	LODW			;Allocation table displacement
	SEG	CS
	ADD	AX,[FATBASE]
	STOW			;FAT
	MOV	DL,0
	SHR	DX		;FAT size in bytes
	ADD	AX,DX
	CMP	AX,BP		;Bigger than already allocated
	JBE	SMFAT
	MOV	BP,AX
SMFAT:
	INC	CH		;Next I/O device number
	DEC	CL
	JNZ	PERDEV
	ADD	BP,15		;True start of free space
	MOV	CL,4
	SHR	BP,CL		;First free segment
	XOR	AX,AX
	MOV	DS,AX
	MOV	ES,AX
	MOV	DI,INTBASE
	MOV	AX,QUIT
	STOW			;Set abort address--displacement
	MOV	AX,CS
	MOV	B,[ENTRYPOINT],LONGJUMP
	MOV	[ENTRYPOINT+1],ENTRY
	MOV	[ENTRYPOINT+3],CS
	STOW
	STOW
	STOW
	MOV	[INTBASE+4],COMMAND
	MOV	DI,INTBASE+14H
	MOV	AX,BIOSREAD
	STOW
	MOV	AX,BIOSSEG
	STOW
	STOW	;Add 2 to DI
	STOW
	MOV	[INTBASE+18H],BIOSWRITE
	MOV	DX,CS
	MOV	DS,DX
	ADD	DX,BP
	MOV	[DMAADD],80H
	MOV	[DMAADD+2],DX
	MOV	AX,[DRVTAB]
	MOV	[CURDRVPT],AX
	MOV	CX,DX
	MOV	BX,0FH
MEMSCAN:
	INC	CX
	JZ	HAVMEM
	MOV	DS,CX
	MOV	AL,[BX]
	NOT	AL
	MOV	[BX],AL
	CMP	AL,[BX]
	NOT	AL
	MOV	[BX],AL
	JZ	MEMSCAN
HAVMEM:
	SEG	CS
	MOV	[ENDMEM],CX
	XOR	CX,CX
	MOV	DS,CX
	MOV	[EXIT],100H
	MOV	[EXIT+2],DX
	MOV	[INTBASE+0CH],100H
	MOV	[INTBASE+0EH],DX
	CALL	SETMEM
	MOV	SI,HEADER
	CALL	OUTMES
	RET	L

QUIT:
	MOV	AH,0
	JP	SAVREGS

COMMAND: ;Interrupt call entry point
	CMP	AH,MAXCOM
	JBE	SAVREGS
BADCALL:
	MOV	AL,0
IRET:	IRET

ENTRY:	;System call entry point and dispatcher
	POP	AX		;IP from the long call at 5
	POP	AX		;Segment from the long call at 5
	SEG	CS
	POP	[TEMP]		;IP from the CALL 5
	PUSHF			;Start re-ordering the stack
	DI
	PUSH	AX		;Save segment
	SEG	CS
	PUSH	[TEMP]		;Stack now ordered as if INT had been used
	CMP	CL,MAXCALL	;This entry point doesn't get as many calls
	JA	BADCALL
	MOV	AH,CL
SAVREGS:
	SEG	CS
	MOV	[SPSAVE],SP
	SEG	CS
	MOV	[SSSAVE],SS
	INC	SP
	INC	SP
	SEG	CS
	POP	[TEMP]
	MOV	SP,CS
	MOV	SS,SP
	MOV	SP,STACK
	PUSH	ES
	PUSH	DS
	PUSH	BP
	PUSH	DI
	PUSH	SI
	PUSH	DX
	PUSH	CX
	PUSH	BX
	PUSH	AX
	MOV	BL,AH
	MOV	BH,0
	SHL	BX
	UP
	SEG	CS
	CALL	[BX+DISPATCH]
	SEG	CS
	MOV	[AXSAVE],AL
	POP	AX
	POP	BX
	POP	CX
	POP	DX
	POP	SI
	POP	DI
	POP	BP
	POP	DS
	POP	ES
	POP	SS
	SEG	CS
	MOV	SP,[SPSAVE]
	IRET

DISPATCH:
; Standard Functions
	DW	ABORT		;0
	DW	CONIN
	DW	CONOUT
	DW	READER
	DW	PUNCH
	DW	LIST		;5
	DW	RAWIO
	DW	GETIO
	DW	SETIO
	DW	PRTBUF
	DW	BUFIN		;10
	DW	CONSTAT
	DW	VERSION
	DW	DSKRESET
	DW	SELDSK
	DW	OPEN		;15
	DW	CLOSE
	DW	SRCHFRST
	DW	SRCHNXT
	DW	DELETE
	DW	SEQRD		;20
	DW	SEQWRT
	DW	CREATE
	DW	RENAME
	DW	INUSE
	DW	CURDRV		;25
	DW	SETDMA
	DW	GETFATPT
	DW	WRTPROT
	DW	GETRDONLY
	DW	SETATTRIB	;30
	DW	GETDSKPT
	DW	USERCODE
	DW	RNDRD
	DW	RNDWRT
	DW	FILESIZE	;35
	DW	SETRNDREC
; Extended Functions
	DW	SETVECT
	DW	NEWBASE
	DW	BLKRD
	DW	BLKWRT		;40

VERSION:
GETIO:
SETIO:
WRTPROT:
GETRDONLY:
SETATTRIB:
USERCODE:
	MOV	AL,0
	RET


READER:
	CALL	BIOSAUXIN,BIOSSEG
	RET

PUNCH:
	MOV	AL,DL
	CALL	BIOSAUXOUT,BIOSSEG
	RET


UNPACK:

; Inputs:
;	DS = CS
;	BX = Cluster number
;	BP = Base of drive parameters
;	SI = Pointer to drive FAT
; Outputs:
;	DI = Contents of FAT for given cluster
;	Zero set means DI=0 (free cluster)
; No other registers affected. Fatal error if cluster too big.

	CMP	BX,[BP+MAXCLUS]
	JA	HURTFAT
	LEA	DI,[SI+BX]
	SHR	BX
	MOV	DI,[DI+BX]
	JNC	HAVCLUS
	SHR	DI
	SHR	DI
	SHR	DI
	SHR	DI
	STC
HAVCLUS:
	RCL	BX
	AND	DI,0FFFH
	RET
HURTFAT:
	MOV	SI,BADMES
	CALL	OUTMES
	JMP	ERROR


PACK:

; Inputs:
;	DS = CS
;	BX = Cluster number
;	DX = Data
;	SI = Pointer to drive FAT
; Outputs:
;	The data is stored in the FAT at the given cluster.
;	BX,DX,DI all destroyed
;	No other registers affected

	MOV	DI,BX
	SHR	BX
	ADD	BX,SI
	ADD	BX,DI
	SHR	DI
	MOV	DI,[BX]
	JNC	ALIGNED
	SHL	DX
	SHL	DX
	SHL	DX
	SHL	DX
	AND	DI,0FH
	JP	PACKIN
ALIGNED:
	AND	DI,0F000H
PACKIN:
	OR	DI,DX
	MOV	[BX],DI
	RET

GETFILE:

; Inputs:
;	DS,DX point to FCB
; Function:
;	Find file name in disk directory. First byte is
;	drive number (0=current disk). "?" matches any
;	character.
; Outputs:
;	Carry set if file not found
;	ELSE
;	BP = Base of drive parameters
;	DS = CS
;	ES = CS
;	AL = Directory record number
;	BX = Pointer into directory buffer
;	SI = Pointer to First Cluster field in directory entry
;	[DIRBUF] has directory record with match
;	[NAME1] has file name
; All other registers destroyed.

	CALL	MOVNAME
	JC	RET		;Bad file name?
FINDNAME:
	MOV	AX,CS
	MOV	DS,AX
	MOV	AL,0
RDIRREC:
	PUSH	AX
	CALL	DIRREAD
	POP	AX
	MOV	BX,DIRBUF-16
CONTSRCH:
	CALL	NEXTENT
	JZ	RET
NDIRREC:
	INC	AL		;Next directory record
	CMP	AL,[BP+DIRSIZ]
	JB	RDIRREC
	STC
	RET

NEXTENT:
	ADD	BX,16
	CMP	BX,DIRBUF+127
	JA	RET
	CMP	B,[BX],0E5H
	JZ	NEXTENT
	MOV	SI,BX
	MOV	DI,NAME1
	MOV	CX,11
WILDCRD:
	REPE
	CMPB
	JZ	RET
	CMP	B,[DI-1],"?"
	JZ	WILDCRD
	JP	NEXTENT


DELETE:	; System call 19
	CALL	GETFILE
	JC	ERRET
	PUSH	AX
	PUSH	BX
	CALL	FATREAD
	POP	BX
DELFILE:
	MOV	B,[BX],0E5H
	PUSH	BX
	MOV	BX,[BX+11]
	MOV	SI,[BP+FAT]
	OR	BX,BX
	JZ	DELNXT
	CMP	BX,[BP+MAXCLUS]
	JA	DELNXT
	CALL	RELEASE
DELNXT:
	POP	BX
	CALL	NEXTENT
	JZ	DELFILE
	POP	AX
	PUSH	AX
	CALL	DIRWRITE
	POP	AX
	CALL	NDIRREC
	PUSH	AX
	JNC	DELFILE
	POP	AX
	CALL	FATWRT
	XOR	AL,AL
	RET


RENAME:	;System call 23
	CALL	MOVNAME
	JC	ERRET
	ADD	SI,5
	MOV	DI,NAME2
	CALL	LODNAME
	CALL	FINDNAME
	JC	ERRET
SAVDREC:
	MOV	AH,AL
RENFIL:
	MOV	DI,BX
	MOV	SI,NAME2
	MOV	CX,11
NEWNAM:
	LODB
	CMP	AL,"?"
	JZ	NOCHG
	MOV	[DI],AL
NOCHG:
	INC	DI
	LOOP	NEWNAM
	CALL	NEXTENT
	JZ	RENFIL
	MOV	AL,AH
	PUSH	AX
	CALL	DIRWRITE
	POP	AX
	CALL	NDIRREC
	JNC	SAVDREC		;New record read, save current number
	XOR	AL,AL
	RET

ERRET:
	MOV	AL,-1
	RET


MOVNAME:

; Inputs:
;	DS, DX point to FCB
; Outputs:
;	ES = CS
;	If file name OK:
;	BP has base of driver parameters
;	[NAME1] has name in upper case
; All registers except DX destroyed
; Carry set if bad file name or drive

	MOV	AX,CS
	MOV	ES,AX
	MOV	DI,NAME1
	MOV	SI,DX
	LODB
	SEG	ES
	CMP	[NUMDRV],AL
	JC	RET
	CBW
	XCHG	AX,BP
	SHL	BP
	MOV	BP,[BP+CURDRVPT]
LODNAME:
; This entry point copies a file name from DS,SI
; to ES,DI converting to upper case.
	MOV	CX,11
MOVCHK:
	LODB
	AND	AL,7FH
	CMP	AL,60H
	JLE	CASEOK
	AND	AL,5FH
CASEOK:
	CMP	AL,20H
	JC	RET
	STOB
	LOOP	MOVCHK
	RET

OPEN:	;System call 15
	PUSH	DX
	PUSH	DS
	CALL	GETFILE
DOOPEN:
; Enter here to perform OPEN on file already found
; in directory. DS=ES=CS, BX points to directory
; entry in DIRBUF, and the top of the stack has the
; address and segment of the FCB to be opened. This
; entry point is used by CREATE.
	POP	ES
	POP	DI
	JC	ERRET
	MOV	AH,[BP+DRVNUM]
	INC	AH
	SEG	ES
	MOV	[DI],AH
	SEG	ES
	MOV	[DI+EXTENT],0	;Set extent field to 0
	ADD	DI,16		;Point to entry pos. field
	MOV	CX,BX
	SUB	CX,DIRBUF
	MOV	AH,CL
	STOW			;directory location
	MOV	AX,BP
	STOW			;pointer to driver parameters
	LEA	SI,[BX+11]
	LODW			;Get starting cluster
	STOW			; first cluster
	STOW			; last cluster accessed
	LODB
	SHL	AL
	LODW
	RCL	AX
	STOW			; size of file in records
	XOR	AX,AX
	STOW			; position of last cluster
	STOW			; file not dirty

FATREAD:
	TEST	B,[BP+DIRTYFAT],-1
	JNZ	RET
	CALL	FIGFAT
NEXTFAT:
	PUSH	DX
	PUSH	CX
	PUSH	BX
	PUSH	AX
	CALL	DREAD
	OR	AL,AL
	POP	AX
	POP	BX
	POP	CX
	POP	DX
	JNZ	BADFAT
	SUB	AL,[BP+FATCNT]
	JZ	RET
	NEG	AL
;{Insert error code here. AL=number of bad fats.
;Since one good FAT was read, should include option
;to rewrite all FATs.}
	JP	FATWRT

BADFAT:
	ADD	DX,CX
	DEC	AL
	JNZ	NEXTFAT
	POP	BP
;{Insert error code here. All FATs on drive are bad.}
	MOV	SI,BADFATMES
	CALL	HARDERR
	JP	FATREAD

CLOSE:	;System call 16
	MOV	DI,DX
	TEST	B,[DI+DIRTYFIL],-1
	JZ	NOFLSH
	PUSH	DI
	MOV	BP,[DI+DRVBP]
	MOV	AL,[BP+DRVNUM]
	CALL	BIOSFLUSH,BIOSSEG
	POP	DI
NOFLSH:
	TEST	B,[DI+SIZCHG],-1
	JZ	OKRET
	MOV	DX,DI
	PUSH	DX
	PUSH	DS
	CALL	GETFILE
	POP	ES
	POP	DI
	JC	BADCLOSE
	MOV	CX,BX
	SUB	CX,DIRBUF
	MOV	AH,CL
	SEG	ES
	CMP	AX,[DI+ENTPOS]
	JNZ	BADCLOSE
	SEG	ES
	MOV	CX,[DI+FIRCLUS]
	MOV	[BX+11],CX
	SEG	ES
	MOV	DX,[DI+FILSIZ]
	SHR	DX
	MOV	[BX+14],DX
	MOV	DL,0
	RCR	DL
	MOV	[BX+13],DL
	CALL	DIRWRITE

CHKFATWRT:
; Do FATWRT only if FAT is dirty

	TEST	B,[BP+DIRTYFAT],-1
	JZ	OKRET

FATWRT:

; Inputs:
;	DS = CS
;	BP = Base of drive parameter table
; Function:
;	Write the FAT back to disk and reset FAT
;	dirty bit.
; Outputs:
;	AL = 0
;	BP unchanged
; All other registers destroyed

	MOV	B,[BP+DIRTYFAT],0
	CALL	FIGFAT
EACHFAT:
	PUSH	DX
	PUSH	CX
	PUSH	BX
	PUSH	AX
	CALL	DWRITE
	POP	AX
	POP	BX
	POP	CX
	POP	DX
	ADD	DX,CX
	DEC	AL
	JNZ	EACHFAT
OKRET:
	MOV	AL,0
	RET

BADCLOSE:
	MOV	B,[BP+DIRTYFAT],0
	MOV	AL,-1
	RET


FIGFAT:
; Loads registers with values needed to read or
; write a FAT.
	MOV	AL,[BP+FATCNT]
	MOV	BX,[BP+FAT]
	MOV	CL,[BP+FATSIZ]	;No. of records occupied by FAT
	MOV	CH,0
	MOV	DX,[BP+FIRFAT]	;Record number of start of FATs
	RET


DIRCOMP:
; Prepare registers for directory read or write
	CBW
	ADD	AX,[BP+FIRDIR]
	MOV	DX,AX
	MOV	BX,DIRBUF
	MOV	CX,1
	RET


CREATE:	;System call 22
	CALL	MOVNAME
	JC	ERRET3
	MOV	DI,NAME1
	MOV	CX,11
	MOV	AL,"?"
	REPNE
	SCAB
	JZ	ERRET3
	PUSH	DX
	PUSH	DS
	MOV	AX,CS
	MOV	DS,AX
	XOR	AX,AX
RDIRREC2:
	PUSH	AX
	CALL	DIRREAD
	POP	AX
	MOV	DI,DIRBUF-16
	MOV	CX,8
FNDFRE:
	ADD	DI,16
	CMP	B,[DI],0E5H
	LOOPNE	FNDFRE
	JZ	FREESPOT
	INC	AL
	CMP	AL,[BP+DIRSIZ]
	JC	RDIRREC2
	POP	DS
	POP	DX
ERRET3:
	MOV	AL,-1
	RET
FREESPOT:
	MOV	BX,DI
	MOV	SI,NAME1
	MOV	CX,5
	MOVB
	REP
	MOVW
	XCHG	AL,AH
	MOV	CL,5
	REP
	STOB
	XCHG	AL,AH
	PUSH	AX
	PUSH	BX
	CALL	DIRWRITE
	POP	BX
	POP	AX
	JMP	DOOPEN


DIRREAD:

; Inputs:
;	DS = CS
;	AL = Directory block number
;	BP = Base of drive parameters
; Function:
;	Read the directory block into DIRBUF.
; Outputs:
;	BP unchanged
; All other registers destroyed.

	CALL	DIRCOMP

DREAD:

; Inputs:
;	BX,DS = Transfer address
;	CX = Number of records
;	DX = Absolute record number
;	BP = Base of drive parameters
; Function:
;	Calls BIOS to perform disk read. If BIOS reports
;	errors, will call HARDERR for further action.
; Outputs:
;	AL = 0 if no error, otherwise non-zero
; BP preserved. All other registers destroyed.

	MOV	AL,[BP+DRVNUM]
	PUSH	BP
	PUSH	BX
	PUSH	CX
	PUSH	DX
	CALL	BIOSREAD,BIOSSEG
	POP	DX
	POP	DI
	POP	BX
	POP	BP
	JC	HARDREAD
	XOR	AL,AL
	RET

HARDREAD:
	MOV	SI,RDERRMES
	CALL	HARDERR
	JP	DREAD

DIRWRITE:

; Inputs:
;	DS = CS
;	AL = Directory block number
;	BP = Base of drive parameters
; Function:
;	Write the directory block into DIRBUF.
; Outputs:
;	BP unchanged
; All other registers destroyed.

	CALL	DIRCOMP


DWRITE:

; Inputs:
;	BX,DS = Transfer address
;	CX = Number of records
;	DX = Absolute record number
;	BP = Base of drive parameters
; Function:
;	Calls BIOS to perform disk write. If BIOS reports
;	errors, will call HARDERR for further action.
; Outputs:
;	AL = 0 if no error, otherwise non-zero
; BP preserved. All other registers destroyed.

	MOV	AL,[BP+DRVNUM]
	MOV	AH,0
	CMP	DX,[BP+FIRREC]
	RCR	AH
	PUSH	BP
	PUSH	BX
	PUSH	CX
	PUSH	DX
	CALL	BIOSWRITE,BIOSSEG
	POP	DX
	POP	DI
	POP	BX
	POP	BP
	JC	HARDWRITE
	XOR	AL,AL
	RET
HARDWRITE:
	MOV	SI,WRTERRMES
	CALL	HARDERR
	JP	DWRITE

HARDERR:
	SUB	DI,CX
	ADD	DX,DI
	CALL	SHFTDI7
	ADD	BX,DI
	CALL	OUTMES
GETINSTR:
	CALL	IN
	OR	AL,20H
	CMP	AL,"a"
	JZ	ERROR
	CMP	AL,"r"
	JZ	RET
	CMP	AL,"i"
	JZ	IGNORE
	CMP	AL,"c"
	JNZ	GETINSTR
	POP	AX
	MOV	AL,1
	RET
IGNORE:
	POP	AX
	MOV	AL,0
	RET

ABORT:
	SEG	CS
	MOV	DS,[CSLOC]
	XOR	AX,AX
	MOV	ES,AX
	MOV	SI,SAVEXIT
	MOV	DI,EXIT
	MOVW
	MOVW
	MOVW
	MOVW
ERROR:
	MOV	SP,BPSAVE
	MOV	AX,CS
	MOV	DS,AX
	MOV	ES,AX
	CALL	WRTFATS
	XOR	AX,AX
	MOV	DS,AX
	MOV	SI,EXIT
	MOV	DI,EXITHOLD
	MOVW
	MOVW
	POP	BP
	POP	ES
	POP	ES
	POP	DS
	POP	SS
	MOV	SP,[SPSAVE]
	MOV	DS,[DSSAVE]
	SEG	CS
	JMP	L,[EXITHOLD]


SEQRD:	;System call 20
	CALL	GETREC
	MOV	CX,1
	CALL	LOAD
	JCXZ	SETNREX
	INC	AX
	JP	SETNREX

SEQWRT:	;System call 21
	CALL	GETREC
	MOV	CX,1
	CALL	STORE
	JCXZ	SETNREX
	INC	AX
	JP	SETNREX

RNDRD:	;System call 33
	MOV	CX,1
	MOV	DI,DX
	MOV	AX,[DI+RR]
	CALL	LOAD
	JP	FINRND

RNDWRT:	;System call 34
	MOV	CX,1
	MOV	DI,DX
	MOV	AX,[DI+RR]
	CALL	STORE
	JP	FINRND

BLKRD:	;System call 39
	MOV	DI,DX
	MOV	AX,[DI+RR]
	CALL	LOAD
	JP	FINBLK

BLKWRT:	;System call 40
	MOV	DI,DX
	MOV	AX,[DI+RR]
	CALL	STORE
FINBLK:
	MOV	[CXSAVE],CX
	JCXZ	FINRND
	INC	AX
FINRND:
	SEG	ES
	MOV	[DI+RR],AX
SETNREX:
	MOV	CX,AX
	AND	AL,7FH
	SEG	ES
	MOV	[DI+NR],AL
	AND	CL,80H
	ROL	CX
	XCHG	CL,CH
	SEG	ES
	MOV	[DI+EXTENT],CX
	MOV	AL,[DSKERR]
	RET

SETUP:

; Inputs:
;	DS:DI point to FCB
;	AX = Record position in file of disk transfer
;	CX = Record count
; Outputs:
;	DS = CS
;	ES:DI point to FCB
;	CX = No. of records to transfer
;	BP = Base of drive parameters
;	SI = FAT pointer
;	[RECCNT] = Record count
;	[RECPOS] = Record position in file
;	[FCB] = DX
;	[NEXTADD] = Displacement of disk transfer within segment
;	[DSKERR] = 0 (no errors yet)
;	[TRANS] = 0 (No transfers yet)
; If SETUP detects no records will be transfered, it returns 1 level up 
; with CX = 0.

	MOV	BP,[DI+DRVBP]
	MOV	BX,DS
	MOV	ES,BX
	MOV	BX,CS
	MOV	DS,BX
	MOV	[RECPOS],AX
	MOV	[FCB],DX
	MOV	BX,[DMAADD]
	MOV	[NEXTADD],BX
	MOV	B,[DSKERR],0
	MOV	[TRANS],0
	MOV	SI,[BP+FAT]
	ADD	BX,7FH		;See if there is any space left
	JC	SEGEND
	AND	BL,80H
	NEG	BX	;These instructions divide by 128
	ROL	BX
	XCHG	BL,BH
	JNZ	CHKMAX
	MOV	BH,2	;All 512 records OK
CHKMAX:
	CMP	CX,BX
	JBE	SAVCNT
	MOV	CX,BX
	MOV	B,[DSKERR],2	;Flag that trimming took place
SAVCNT:
	MOV	[RECCNT],CX
	RET
SEGEND:
	MOV	B,[DSKERR],2
	MOV	CX,0
	POP	BX
	RET


FNDCLUS:

; Inputs:
;	DS = CS
;	CX = No. of clusters to skip
;	BP = Base of drive parameters
;	SI = FAT pointer
;	ES:DI point to FCB
; Outputs:
;	BX = Last cluster skipped to
;	CX = No. of clusters remaining (0 unless EOF)
;	DX = Position of last cluster
; DI destroyed. No other registers affected.

	SEG	ES
	MOV	BX,[DI+LSTCLUS]
	SEG	ES
	MOV	DX,[DI+CLUSPOS]
	OR	BX,BX
	JZ	NOCLUS
	SUB	CX,DX
	JNB	FINDIT
	ADD	CX,DX
	XOR	DX,DX
	SEG	ES
	MOV	BX,[DI+FIRCLUS]
FINDIT:
	JCXZ	RET
SKPCLP:
	CALL	UNPACK
	CMP	DI,0FFFH
	JZ	RET
	XCHG	BX,DI
	INC	DX
	LOOP	SKPCLP
	RET
NOCLUS:
	INC	CX
	DEC	DX
	RET


LOAD:

; Inputs:
;	DS:DI point to FCB
;	AX = Position in file to read
;	CX = No. of records to read
; Outputs:
;	AX = Position of last record read
;	CX = No. of records read
;	ES:DI point to FCB
;	LSTCLUS, CLUSPOS fields in FCB set

	CALL	SETUP
	SEG	ES
	MOV	BX,[DI+FILSIZ]
	SUB	BX,AX
	JBE	WRTERRJ
	CMP	BX,CX
	JNB	ENUF
	MOV	B,[DSKERR],1
	MOV	[RECCNT],BX
ENUF:
	MOV	CL,[BP+CLUSSHFT]
	SHR	AX,CL
	MOV	CX,AX
	CALL	FNDCLUS
	OR	CX,CX
	JNZ	WRTERR
	MOV	DL,[RECPOS]
	AND	DL,[BP+CLUSMSK]
	MOV	CX,[RECCNT]
RDLP:
	CALL	OPTIMIZE
	PUSH	DI
	PUSH	AX
	PUSH	DS
	MOV	DS,[DMAADD+2]
	CALL	DREAD
	POP	DS
	POP	CX
	POP	BX
	JCXZ	SETFCB
	MOV	DL,0
	CMP	BX,0FFFH
	JNZ	RDLP
	MOV	B,[DSKERR],1

SETFCB:
	MOV	AX,[CLUSNUM]
	MOV	DI,[FCB]
	SEG	ES
	MOV	[DI+LSTCLUS],AX
	MOV	AX,[RECPOS]
	MOV	BX,[TRANS]
	ADD	AX,BX
	SEG	ES
	CMP	AX,[DI+FILSIZ]
	JBE	SAMSIZ
	SEG	ES
	MOV	[DI+FILSIZ],AX
	SEG	ES
	MOV	B,[DI+SIZCHG],-1
SAMSIZ:
	DEC	AX
	MOV	DX,AX
	MOV	CL,[BP+CLUSSHFT]
	SHR	DX,CL
	SEG	ES
	MOV	[DI+CLUSPOS],DX
	MOV	CX,BX
	RET

WRTERRJ:JP	WRTERR

HAVSTART:
	MOV	CX,AX
	PUSH	BX
	CALL	FNDCLUS
	JCXZ	WRCLUS
	CALL	ALLOCATE
	POP	BX
	JNC	NOSKIP
WRTERR:
	MOV	B,[DSKERR],1
LVDSK:
	MOV	AX,[RECPOS]
	XOR	CX,CX
	MOV	DI,[FCB]
	RET
WRTEOF:
	MOV	CL,[BP+CLUSSHFT]
	SHR	AX,CL
	MOV	CX,AX
	CALL	FNDCLUS
	OR	CX,CX
	JNZ	LVDSK
	MOV	DX,0FFFH
	MOV	B,[BP+DIRTYFAT],-1
	MOV	DI,[FCB]
	MOV	AX,[RECPOS]
	SEG	ES
	MOV	[DI+FILSIZ],AX
	SEG	ES
	MOV	B,[DI+SIZCHG],-1
	XOR	CX,CX
	RET

STORE:

; Inputs:
;	DS:DI point to FCB
;	AX = Position in file of disk transfer
;	CX = Record count
; Outputs:
;	AX = Position of last record written
;	CX = No. of records written
;	ES:DI point to FCB
;	LSTCLUS, CLUSPOS fields in FCB set

	CALL	SETUP
	JCXZ	WRTEOF
	MOV	BX,CX
	ADD	BX,AX
	DEC	BX
	MOV	CL,[BP+CLUSSHFT]
	SHR	AX,CL
	SHR	BX,CL
	MOV	CX,AX
	MOV	AX,BX
	CALL	FNDCLUS
	SUB	AX,DX		;Last cluster minus current cluster
	JCXZ	HAVSTART	;See if no more data
	PUSH	CX		;No. of clusters of first
	MOV	CX,AX
	CALL	ALLOCATE
	POP	CX
	JC	WRTERR
	DEC	CX
	JZ	NOSKIP
	CALL	SKPCLP
	PUSH	BX
WRCLUS:
	POP	BX
NOSKIP:
	MOV	DL,[RECPOS]
	AND	DL,[BP+CLUSMSK]
	MOV	CX,[RECCNT]
WRTLP:
	CALL	OPTIMIZE
	PUSH	DI
	PUSH	AX
	PUSH	DS
	MOV	DS,[DMAADD+2]
	CALL	DWRITE
	POP	DS
	POP	CX
	POP	BX
	MOV	DL,0
	OR	CX,CX
	JNZ	WRTLP
	CALL	SETFCB
	SEG	ES
	MOV	B,[DI+DIRTYFIL],-1
	RET


OPTIMIZE:

; Inputs:
;	DS = CS
;	BX = Physical cluster
;	CX = No. of records
;	DL = record within cluster
;	BP = Base of drives parameters
;	[NEXTADD] = transfer address
; Outputs:
;	AX = No. of records remaining
;	BX = Transfer address
;	CX = No. or records to be transferred
;	DX = Physical record address
;	DI = Next cluster
;	[CLUSNUM] = Last cluster accessed
;	[NEXTADD] updated
; BP unchanged. Note that segment of transfer not set.

	PUSH	DX
	PUSH	BX
	MOV	AL,[BP+CLUSMSK]
	INC	AL		;Number of records per cluster
	MOV	AH,AL
	SUB	AL,DL		;AL = Number of records left in first cluster
	MOV	DX,CX
	MOV	SI,[BP+FAT]
	MOV	CX,0
OPTCLUS:
;AL has number of records available in current cluster
;AH has number of records available in next cluster
;BX has current physical cluster
;CX has number of sequential records found so far
;DX has number of records left to transfer
;SI has FAT pointer
	CALL	UNPACK
	ADD	CL,AL
	ADC	CH,0
	CMP	CX,DX
	JAE	BLKDON
	MOV	AL,AH
	INC	BX
	CMP	DI,BX
	JZ	OPTCLUS
	DEC	BX
FINCLUS:
	MOV	[CLUSNUM],BX	;Last cluster accessed
	SUB	DX,CX		;Number of records still needed
	MOV	AX,DX
	MOV	BX,CX
	XCHG	BL,BH
	ROR	BX
	MOV	SI,[NEXTADD]
	ADD	BX,SI		;Adjust by size of transfer
	MOV	[NEXTADD],BX
	ADD	[TRANS],CX
	POP	DX
	POP	BX
	PUSH	CX
	MOV	CL,[BP+CLUSSHFT]
	DEC	DX
	DEC	DX
	SHL	DX,CL
	OR	DL,BL
	ADD	DX,[BP+FIRREC]
	POP	CX
	MOV	BX,SI
	RET
BLKDON:
	MOV	CX,DX		;Make the total equal to the request
	JP	FINCLUS


GETREC:

; Inputs:
;	DS:DX point to FCB
; Outputs:
;	AX = Record number determined by EXTENT and NR fields
;	DS:DI point to FCB
; BX destroyed. No other registers affected.

	MOV	DI,DX
	MOV	AL,[DI+NR]
	MOV	BX,[DI+EXTENT]
	SHL	AL
	SHR	BX
	RCR	AL
	MOV	AH,BL
	RET


ALLOCATE:

; Inputs:
;	DS = CS
;	ES = Segment of FCB
;	BX = Last cluster of file (0 if null file)
;	CX = No. of clusters to allocate
;	DX = Position of cluster BX
;	BP = Base of drive parameters
;	SI = FAT pointer
;	[FCB] = Displacement of FCB within segment
; Outputs:
;	IF insufficient space
;	  THEN
;	Carry set
;	  ELSE
;	Carry clear
;	BX = First cluster allocated
;	FAT is fully updated including dirty bit
;	FIRCLUS field of FCB set if file was null
; SI,BP unchanged. All other registers destroyed.

	PUSH	BX
	MOV	AX,BX
ALLOC:
	MOV	DX,BX
FINDFRE:
	INC	BX
	CMP	BX,[BP+MAXCLUS]
	JL	TRYOUT
	CMP	AX,1
	JG	TRYIN
	POP	BX
	MOV	DX,0FFFH
	CALL	RELBLKS
	OR	[SI],0FFFH
	STC
	RET

TRYOUT:
	CALL	UNPACK
	JZ	HAVFRE
TRYIN:
	DEC	AX
	JLE	FINDFRE
	XCHG	AX,BX
	CALL	UNPACK
	JZ	HAVFRE
	XCHG	AX,BX
	JP	FINDFRE
HAVFRE:
	XCHG	BX,DX
	MOV	AX,DX
	CALL	PACK
	MOV	BX,AX
	LOOP	ALLOC
	MOV	DX,0FFFH
	CALL	PACK
	MOV	B,[BP+DIRTYFAT],-1
	POP	BX
	CALL	UNPACK
	XCHG	BX,DI
	OR	DI,DI
	JNZ	RET
	MOV	DI,[FCB]
	SEG	ES
	MOV	[DI+FIRCLUS],BX
	OR	[SI],0FFFH
	RET


RELEASE:

; Inputs:
;	DS = CS
;	BX = Cluster in file
;	SI = FAT pointer
;	BP = Base of drive parameters
; Function:
;	Frees cluster chain starting with [BX]
; AX,BX,DX,DI all destroyed. Other registers unchanged.

	XOR	DX,DX
RELBLKS:
; Enter here with DX=0FFFH to put an end-of-file mark
; in the first cluster and free the rest in the chain.
	CALL	UNPACK
	JZ	RET
	MOV	AX,DI
	CALL	PACK
	CMP	AX,0FFFH
	MOV	BX,AX
	JNZ	RELEASE
	RET


GETEOF:

; Inputs:
;	BX = Cluster in a file
;	SI = Base of drive FAT
;	DS = CS
; Outputs:
;	BX = Last cluster in the file
; DI destroyed. No other registers affected.

	CALL	UNPACK
	CMP	DI,0FFFH
	JZ	RET
	MOV	BX,DI
	JP	GETEOF


SRCHFRST: ;System call 17
	CALL	GETFILE
SAVPLCE:
; Search-for-next enters here to save place and report
; findings.
	JC	KILLSRCH
	MOV	[SRCHDON],AL
	MOV	[PDIR],BX
	MOV	[SRCHBP],BP
;Information in directory entry must be copied into the first
; 16 bytes starting at the disk transfer address.
	MOV	SI,BX
	LES	DI,[DMAADD]
	MOV	CX,8
	REP
	MOVW
	MOV	AL,0
	RET

KILLSRCH:
	MOV	AL,-1
	MOV	[SRCHDON],AL
	RET


SRCHNXT: ;System call 18
	MOV	AX,CS
	MOV	ES,AX
	MOV	DS,AX
	MOV	AL,[SRCHDON]
	CMP	AL,-1
	JZ	RET
	MOV	BX,[PDIR]
	MOV	BP,[SRCHBP]
	CALL	CONTSRCH
	JP	SAVPLCE


FILESIZE: ;System call 35
	PUSH	DI
	PUSH	DX
	CALL	GETFILE
	POP	DI
	POP	ES
	MOV	AL,-1
	JC	RET
	ADD	DI,33		;Write size in RR field
	LEA	SI,[BX+13]
	LODB
	SHL	AL
	LODW
	RCL	AX		;Round to nearest record
	STOW
	MOV	AL,0
	RCL	AL
	STOB
	RET


SETDMA:	;System call 26
	SEG	CS
	MOV	[DMAADD],DX
	SEG	CS
	MOV	[DMAADD+2],DS
	RET

GETFATPT: ;System call 27
	MOV	AX,CS
	MOV	DS,AX
	MOV	[DSSAVE],CS
	MOV	BP,[CURDRVPT]
	CALL	FATREAD
	MOV	BX,[BP+FAT]
	MOV	AL,[BP+CLUSMSK]
	INC	AL
	MOV	DX,[BP+MAXCLUS]
	DEC	DX
	MOV	B,[BP+DIRTYFAT],-1
	MOV	[BXSAVE],BX
	MOV	[DXSAVE],DX
	RET


GETDSKPT: ;System call 31
	SEG	CS
	MOV	[DSSAVE],CS
	SEG	CS
	MOV	BX,[CURDRVPT]
	SEG	CS
	MOV	[BXSAVE],BX
	RET


DSKRESET: ;System call 13
	SEG	CS
	MOV	[DMAADD+2],DS
	MOV	AX,CS
	MOV	DS,AX
	MOV	[DMAADD],80H
	MOV	AX,[CURDRVPT+2]
	MOV	[CURDRVPT],AX
WRTFATS:
; DS=CS. Writes back all dirty FATs. All registers destroyed.
	MOV	CL,[NUMDRV]
	MOV	CH,0
	MOV	SI,CURDRVPT+2
WRTFAT:
	LODW
	PUSH	CX
	PUSH	SI
	MOV	BP,AX
	CALL	CHKFATWRT
	POP	SI
	POP	CX
	LOOP	WRTFAT
	MOV	AL,-1
	CALL	BIOSFLUSH,BIOSSEG
	RET


CURDRV:	;System call 25
	SEG	CS
	MOV	BP,[CURDRVPT]
	MOV	AL,[BP+DRVNUM]
	RET


INUSE:	;System call 24
	MOV	AX,CS
	MOV	DS,AX
	MOV	CL,[NUMDRV]
	MOV	CH,0
	MOV	SI,CX
	SHL	SI
	ADD	SI,CURDRVPT
	MOV	BX,0
	DOWN
CHKUSE:
	LODW
	MOV	BP,AX
	TEST	B,[BP+DIRTYFAT],-1
	JZ	SETBIT
	STC
SETBIT:
	RCL	BX
	LOOP	CHKUSE
	MOV	AL,BL
	RET


SETRNDREC: ;System call 36
	CALL	GETREC
	MOV	[DI+33],AX
	MOV	AL,0
	JZ	BIGRR
	INC	AL
BIGRR:
	MOV	[DI+35],AL
	RET


SELDSK:	;System call 14
	MOV	DH,0
	MOV	BX,DX
	PUSH	CS
	POP	DS
	CMP	BL,[NUMDRV]
	JGE	RET
	SHL	BX
	MOV	AX,[BX+CURDRVPT+2]
	MOV	[CURDRVPT],AX
	RET


BUFIN:	;System call 10
	MOV	AX,CS
	MOV	ES,AX
	MOV	SI,DX
	MOV	CH,0
	LODW
	OR	AL,AL
	JZ	RET
	MOV	BL,AH
	MOV	BH,CH
	CMP	AL,BL
	JBE	NOEDIT
	CMP	B,[BX+SI],0DH
	JZ	EDITON
NOEDIT:
	MOV	BL,CH
EDITON:
	MOV	DL,AL
	DEC	DX
NEWLIN:
	SEG	CS
	MOV	AL,[CARPOS]
	SEG	CS
	MOV	[STARTPOS],AL
	PUSH	SI
	MOV	DI,INBUF
	MOV	AH,CH
	MOV	BH,CH
	MOV	DH,CH
GETCH:
	CALL	IN
	CMP	AL,7FH
	JZ	BACKSP
	CMP	AL,8
	JZ	BACKSP
	CMP	AL,13
	JZ	ENDLIN
	CMP	AL,10
	JZ	PHYCRLF
	CMP	AL,"X"-"@"
	JZ	KILNEW
	CMP	AL,ESCCH
	JZ	ESC
SAVCH:
	CMP	DH,DL
	JAE	GETCH
	STOB
	INC	DH
	CALL	OUT
	OR	AH,AH
	JNZ	GETCH
	CMP	BH,BL
	JAE	GETCH
	INC	SI
	INC	BH
	JP	GETCH

ESC:
	CALL	IN
	MOV	CL,ESCTABLEN
	PUSH	DI
	MOV	DI,ESCTAB
	REPNE
	SCAB
	POP	DI
	AND	CL,0FEH
	MOV	BP,CX
	JMP	[BP+ESCFUNC]

ENDLIN:
	STOB
	CALL	OUT
	POP	DI
	MOV	[DI-1],DH
	INC	DH
COPYNEW:
	MOV	BP,ES
	MOV	BX,DS
	MOV	ES,BX
	MOV	DS,BP
	MOV	SI,INBUF
	MOV	CL,DH
	REP
	MOVB
	RET
CRLF:
	MOV	AL,13
	CALL	OUT
	MOV	AL,10
	JMP	OUT

PHYCRLF:
	CALL	CRLF
	JP	GETCH

KILNEW:
	MOV	AL,"\"
	CALL	OUT
	POP	SI
PUTNEW:
	CALL	CRLF
	JMP	NEWLIN

BACKSP:
	OR	DH,DH
	JZ	OLDBAK
	CALL	BACKUP
	SEG	ES
	MOV	AL,[DI]
	CMP	AL," "
	JAE	OLDBAK
	CMP	AL,9
	JZ	BAKTAB
	CALL	BACKMES
OLDBAK:
	OR	AH,AH
	JNZ	GETCH1
	OR	BH,BH
	JZ	GETCH1
	DEC	BH
	DEC	SI
GETCH1:
	JMP	GETCH
BAKTAB:
	PUSH	DI
	DEC	DI
	DOWN
	MOV	CL,DH
	MOV	AL," "
	PUSH	BX
	MOV	BL,7
	JCXZ	FIGTAB
FNDPOS:
	SCAB
	JNA	CHKCNT
	SEG	ES
	CMP	B,[DI+1],9
	JZ	HAVTAB
	DEC	BL
CHKCNT:
	LOOP	FNDPOS
FIGTAB:
	SEG	CS
	SUB	BL,[STARTPOS]
HAVTAB:
	SUB	BL,DH
	ADD	CL,BL
	AND	CL,7
	UP
	POP	BX
	POP	DI
	JZ	OLDBAK
TABBAK:
	CALL	BACKMES
	LOOP	TABBAK
	JP	OLDBAK
BACKUP:
	DEC	DH
	DEC	DI
BACKMES:
	MOV	AL,8
	CALL	OUT
	MOV	AL," "
	CALL	OUTCH
	MOV	AL,8
	JMP	OUTCH

TWOESC:
	MOV	AL,ESCCH
	JMP	SAVCH

COPYLIN:
	MOV	CL,BL
	SUB	CL,BH
	JP	COPYEACH

COPYSTR:
	CALL	FINDOLD
	JP	COPYEACH

COPYONE:
	MOV	CL,1
COPYEACH:
	CMP	DH,DL
	JZ	GETCH2
	CMP	BH,BL
	JZ	GETCH2
	LODB
	STOB
	CALL	OUT
	INC	BH
	INC	DH
	LOOP	COPYEACH
GETCH2:
	JMP	GETCH

SKIPONE:
	CMP	BH,BL
	JZ	GETCH2
	INC	BH
	INC	SI
	JMP	GETCH

SKIPSTR:
	CALL	FINDOLD
	ADD	SI,CX
	ADD	BH,CL
	JMP	GETCH

FINDOLD:
	CALL	IN
	MOV	CL,BL
	SUB	CL,BH
	JZ	NOTFND
	DEC	CX
	JZ	NOTFND
	PUSH	ES
	PUSH	DS
	POP	ES
	PUSH	DI
	MOV	DI,SI
	INC	DI
	REPNE
	SCAB
	POP	DI
	POP	ES
	JNZ	NOTFND
	NOT	CL
	ADD	CL,BL
	SUB	CL,BH
	RET
NOTFND:
	POP	BP
	JMP	GETCH

REEDIT:
	MOV	AL,"@"
	CALL	OUT
	POP	DI
	PUSH	DI
	PUSH	ES
	PUSH	DS
	CALL	COPYNEW
	POP	DS
	POP	ES
	POP	SI
	MOV	BL,DH
	JMP	PUTNEW

ENTERINS:
	MOV	AH,-1
	JMP	GETCH

EXITINS:
	MOV	AH,0
	JMP	GETCH

ESCFUNC:
	DW	GETCH
	DW	TWOESC
	DW	EXITINS
	DW	ENTERINS
	DW	BACKSP
	DW	REEDIT
	DW	KILNEW
	DW	COPYLIN
	DW	SKIPSTR
	DW	COPYSTR
	DW	SKIPONE
	DW	COPYONE

CONOUT:	;System call 2
	MOV	AL,DL
OUT:
	CMP	AL,20H
	JB	CTRLOUT
	CMP	AL,7FH
	JZ	OUTCH
	SEG	CS
	INC	B,[CARPOS]
OUTCH:
	CALL	BIOSOUT,BIOSSEG
	SEG	CS
	TEST	B,[PFLAG],-1
	JZ	STATCHK
	CALL	BIOSPRINT,BIOSSEG
STATCHK:
	CALL	BIOSSTAT,BIOSSEG
	JZ	RET
INCHK:
	CALL	BIOSIN,BIOSSEG
	CMP	AL,'S'-'@'
	JNZ	NOSTOP
	CALL	BIOSIN,BIOSSEG
NOSTOP:
	CMP	AL,'P'-'@'
	JZ	PRINTON
	CMP	AL,'N'-'@'
	JZ	PRINTOFF
	CMP	AL,'C'-'@'
	JNZ	RET
	INT	CONTC		;Execute user Ctrl-C handler
	RET

PRINTON:
	SEG	CS
	MOV	B,[PFLAG],1
	RET
PRINTOFF:
	SEG	CS
	MOV	B,[PFLAG],0
	RET
CTRLOUT:
	CMP	AL,10
	JZ	OUTCH
	CMP	AL,13
	JZ	ZERPOS
	CMP	AL,8
	JZ	BACKPOS
	CMP	AL,9
	JZ	TAB
	PUSH	AX
	MOV	AL,"^"
	CALL	OUT
	POP	AX
	OR	AL,40H
	JP	OUT

ZERPOS:
	SEG	CS
	MOV	B,[CARPOS],0
	JP	OUTCH
BACKPOS:
	SEG	CS
	DEC	B,[CARPOS]
	JP	OUTCH

TAB:
	MOV	AL,0
	SEG	CS
	XCHG	AL,[CARPOS]
	OR	AL,0F8H
	NEG	AL
	PUSH	CX
	MOV	CL,AL
	MOV	CH,0
TABLP:
	MOV	AL," "
	CALL	OUTCH
	LOOP	TABLP
	POP	CX
	RET


CONSTAT: ;System call 11
	CALL	BIOSSTAT,BIOSSEG
	JZ	RET
	OR	AL,-1
	RET


CONIN:	;System call 1
	CALL	INCHK
	PUSH	AX
	CALL	OUT
	POP	AX
	RET


IN:	;Internal input routine
	CALL	INCHK
	JZ	IN
	RET

RAWIO:	;System call 6
	MOV	AL,DL
	CMP	AL,-1
	JNZ	RAWOUT
	CALL	BIOSSTAT,BIOSSEG
	JZ	RET
	CALL	BIOSIN,BIOSSEG
	RET
RAWOUT:
	CALL	BIOSOUT,BIOSSEG
	RET

LIST:	;System call 5
	MOV	AL,DL
	CALL	BIOSPRINT,BIOSSEG
	RET

PRTBUF:	;System call 9
	MOV	SI,DX
OUTSTR:
	LODB
	CMP	AL,"$"
	JZ	RET
	CALL	OUT
	JP	OUTSTR

OUTMES:	;String output for internal messages
	SEG	CS
	LODB
	CMP	AL,"$"
	JZ	RET
	CALL	OUT
	JP	OUTMES


SETVECT: ; Interrupt call 37
	XOR	BX,BX
	MOV	ES,BX
	MOV	BL,AL
	SHL	BX
	SHL	BX
	SEG	ES
	MOV	[BX],DX
	SEG	ES
	MOV	[BX+2],DS
	RET


NEWBASE: ; Interrupt call 38
	MOV	ES,DX
	SEG	CS
	MOV	DS,[CSLOC]
	XOR	SI,SI
	MOV	DI,SI
	MOV	CX,80H
	REP
	MOVW

SETMEM:

; Inputs:
;	DX = Segment
; Function:
;	Completely prepares a program base at the 
;	specified segment.
; Outputs:
;	DS = DX
;	ES = DX
;	[0] has INT 20H
;	[2] = First unavailable segment ([ENDMEM])
;	[5] to [9] form a long call to the entry point
;	[10] to [13] have exit address (from INT 22H)
;	[14] to [17] have ctrl-C exit address (from INT 23H)
; AX,DX,BP unchanged. All other registers destroyed.

	XOR	CX,CX
	MOV	DS,CX
	MOV	ES,DX
	MOV	SI,EXIT
	MOV	DI,SAVEXIT
	MOVW
	MOVW
	MOVW
	MOVW
	SEG	CS
	MOV	CX,[ENDMEM]
	SEG	ES
	MOV	[2],CX
	SUB	CX,DX
	CMP	CX,MAXDIF
	JBE	HAVDIF
	MOV	CX,MAXDIF
HAVDIF:
	MOV	BX,ENTRYPOINTSEG
	SUB	BX,CX
	SHL	CX
	SHL	CX
	SHL	CX
	SHL	CX
	MOV	DS,DX
	MOV	[6],CX
	MOV	[8],BX
	MOV	[0],20CDH	;"INT INTTAB"
	MOV	B,[5],LONGCALL
	RET


SHFTDI7:
	SHL	DI
	SHL	DI
	SHL	DI
	SHL	DI
	SHL	DI
	SHL	DI
	SHL	DI
	RET


;***** DATA AREA *****

BADMES:	DB	13,10,"Bad FAT",13,10,"$"
BADFATMES:DB	13,10,"All FATs on disk are bad",13,10,"$"
RDERRMES:DB	13,10,"Disk read error",13,10,"$"
WRTERRMES:DB	13,10,"Disk write error",13,10,"$"

CARPOS:	DB	0
STARTPOS:DB	0
PFLAG:	DB	0
SRCHDON:DB	-1
PDIR:	DS	2
SRCHBP:	DS	2
EXITHOLD:DS	4
ENDMEM:	DS	2
FATBASE:DS	2
INBUF:	DS	255
DIRBUF:	DS	128
NUMDRV:	DS	1	;Number of drives
NAME1:	DS	11	;File name buffer
NAME2:	DS	11
DMAADD:	DS	4	;User's disk transfer address (disp/seg)
TEMP:
CSLOC:	DS	2
DSKERR:	DS	1
FCB:	DS	2	;Address of user FCB
RECPOS:	DS	2
NEXTADD:DS	2
RECCNT:	DS	2
CLUSNUM:DS	2
TRANS:	DS	2

	DS	50	;Stack space
AXSAVE:	DS	2
BXSAVE:	DS	2
CXSAVE:	DS	2
DXSAVE:	DS	2
SISAVE:	DS	2
DISAVE:	DS	2
BPSAVE:	DS	2
DSSAVE:	DS	2
ESSAVE:	DS	2
STACK:
SSSAVE:	DS	2
SPSAVE:	DS	2

CURDRVPT:DS	2
DRVTAB:				;Address of start of DPBs
