   888888888            666666666         DDDDDDDDDDDD            OOOOOOOOO            SSSSSSSSSSSS
   888888888            666666666         DDDDDDDDDDDD            OOOOOOOOO            SSSSSSSSSSSS
   888888888            666666666         DDDDDDDDDDDD            OOOOOOOOO            SSSSSSSSSSSS
888         888      666                  DDD         DDD      OOO         OOO      SSS            
888         888      666                  DDD         DDD      OOO         OOO      SSS            
888         888      666                  DDD         DDD      OOO         OOO      SSS            
888         888      666                  DDD         DDD      OOO         OOO      SSS            
888         888      666                  DDD         DDD      OOO         OOO      SSS            
888         888      666                  DDD         DDD      OOO         OOO      SSS            
   888888888         666666666666         DDD         DDD      OOO         OOO         SSSSSSSSS   
   888888888         666666666666         DDD         DDD      OOO         OOO         SSSSSSSSS   
   888888888         666666666666         DDD         DDD      OOO         OOO         SSSSSSSSS   
888         888      666         666      DDD         DDD      OOO         OOO                  SSS
888         888      666         666      DDD         DDD      OOO         OOO                  SSS
888         888      666         666      DDD         DDD      OOO         OOO                  SSS
888         888      666         666      DDD         DDD      OOO         OOO                  SSS
888         888      666         666      DDD         DDD      OOO         OOO                  SSS
888         888      666         666      DDD         DDD      OOO         OOO                  SSS
   888888888            666666666         DDDDDDDDDDDD            OOOOOOOOO         SSSSSSSSSSSS   
   888888888            666666666         DDDDDDDDDDDD            OOOOOOOOO         SSSSSSSSSSSS   
   888888888            666666666         DDDDDDDDDDDD            OOOOOOOOO         SSSSSSSSSSSS   




   AAAAAAAAA            888888888            666666666   
   AAAAAAAAA            888888888            666666666   
   AAAAAAAAA            888888888            666666666   
AAA         AAA      888         888      666            
AAA         AAA      888         888      666            
AAA         AAA      888         888      666            
AAA         AAA      888         888      666            
AAA         AAA      888         888      666            
AAA         AAA      888         888      666            
AAA         AAA         888888888         666666666666   
AAA         AAA         888888888         666666666666   
AAA         AAA         888888888         666666666666   
AAAAAAAAAAAAAAA      888         888      666         666
AAAAAAAAAAAAAAA      888         888      666         666
AAAAAAAAAAAAAAA      888         888      666         666
AAA         AAA      888         888      666         666
AAA         AAA      888         888      666         666
AAA         AAA      888         888      666         666
AAA         AAA         888888888            666666666   
AAA         AAA         888888888            666666666   
AAA         AAA         888888888            666666666   




 *START* User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:49:36 Monitor Microsoft 1091 603a4d80j *START*
File: DSKC:86DOS.A86<055>[500,500] Created: 07-Jul-81 17:06:59 Printed: 08-Jul-81 13:49:52
QUEUE Switches:  /FILE:ASCII /COPIES:1 /SPACING:1 /LIMIT:129 /FORMS:NORMAL
00010	
00020	; 86-DOS  High-performance operating system for the 8086  version 1.00 04/28/81
00030	;	by Tim Paterson
00040	
00050	; ****************** Revision History *************************
00060	;          >> EVERY change must noted below!! <<
00070	;
00080	; 0.34 12/29/80 General release, updating all past customers
00090	; 0.42 02/25/81 32-byte directory entries added
00100	; 0.56 03/23/81 Variable record and sector sizes
00110	; 0.60 03/27/81 Ctrl-C exit changes, including register save on user stack
00120	; 0.74 04/15/81 Recognize I/O devices with file names
00130	; 0.75 04/17/81 Improve and correct buffer handling
00140	; 0.76 04/23/81 Correct directory size when not 2^N entries
00150	; 0.80 04/27/81 Add console input without echo, Functions 7 & 8
00160	; 1.00 04/28/81 Renumber for general release
00170	;
00180	; *************************************************************
00190	
00192	EXCESS:	EQU	511		;Make 86-DOS artificially larger
00194	
00200	; Use the switch below to generate code to accept the old 16-byte
00210	; directory entry as well as the new 32-byte entry.
00220	
00230	SMALLDIR:	EQU	0	;1 to enable, 0 to disable
00240	
00250	
00260	; Turn on switch below to allow testing disk code with DEBUG. It sets
00270	; up a different stack for disk I/O (functions > 11) than that used for
00280	; character I/O which effectively makes the DOS re-entrant.
00290	
00300	DSKTEST:	EQU	0	;1 to enable, 0 to disable
00310	
00320	
00330	; Interrupt Entry Points:
00340	
00350	; INTBASE:	ABORT
00360	; INTBASE+4:	COMMAND
00370	; INTBASE+8:	BASE EXIT ADDRESS
00380	; INTBASE+C:	CONTROL-C ABORT
00390	; INTBASE+10H:	FATAL ERROR ABORT
00400	; INTBASE+14H:	BIOS DISK READ
00410	; INTBASE+18H:	BIOS DISK WRITE
00420	; INTBASE+40H:	Long jump to CALL entry point
00430	
00440	
00450	MAXCALL:EQU	36
00460	MAXCOM:	EQU	45
00470	ESCCH:	EQU	0
00480	INTBASE:EQU	80H
00490	INTTAB:	EQU	20H
00500	ENTRYPOINTSEG:	EQU	0CH
00510	ENTRYPOINT:	EQU	INTBASE+40H
00520	CONTC:	EQU	INTTAB+3
00530	EXIT:	EQU	INTBASE+8
00540	LONGJUMP:EQU	0EAH
00550	LONGCALL:EQU	9AH
00560	MAXDIF:	EQU	0FFFH
00570	SAVEXIT:EQU	10
00580					;Date format
00590					;16 15 14 13 11 10 9 8 7 6 5 4 3 2 1 0
00600					; y  y  y  y  y  y y m m m m d d d d d
00610					;
00620					;where y=year,m=month,d=day
00630	
00640	; Field definition for FCBs
00650	
00660		ORG	0
00670		DS	12		;Drive code and name
00680	EXTENT:	DS	2
00690	RECSIZ:	DS	2		;Size of record (user settable)
00700	FILSIZ:	DS	4		;Size of file in bytes
00710	FDATE:	DS	2		;Date of last writing
00720	FILDIRBLK:DS	2		;Location in directory
00730	FIRCLUS:DS	2		;First cluster of file
00740	LSTCLUS:DS	2		;Last cluster accessed
00750	CLUSPOS:DS	2		;Position of last cluster accessed
00760	DIRTYFIL:DS	1		;File has been written to if <>0
00770		ORG	32
00780	NR:	DS	1		;Next record
00790	RR:	DS	3		;Random record
00800	
00810	
00820	; Description of 32-byte directory entry (same as returned by SEARCH FIRST
00830	; and SEARCH NEXT, functions 17 and 18).
00840	
00850	; Location	bytes	Description
00860	
00870	;    0		11	File name and extension ( 0E5H if empty)
00880	;   11		 1	Attributes. Bits 1 or 2 make file hidden
00890	;   12		12	Zero field (for expansion)
00900	;   24		 2	Date. Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
00910	;   26		 2	First allocation unit ( < 4080 )
00920	;   28		 4	File size, in bytes (LSB first, 30 bits max.)
00930	
00940	
00950	; Field definition for Drive Parameter Block
00960	
00970		ORG	0
00980	DRVNUM:	DS	1		;Drive number
00990	SECSIZ:	DS	2		;Size of physical sector in bytes
01000	CLUSMSK:DS	1		;Sectors/cluster - 1
01010	CLUSSHFT:DS	1		;Log2 of sectors/cluster
01020	FIRFAT:	DS	2		;Starting record of FATs
01030	FATCNT:	DS	1		;Number of FATs for this drive
01040	MAXENT:	DS	2		;Number of directory entries
01050	DIRSEC:				;Number of dir. sectors (init temporary)
01060	FIRREC:	DS	2		;First sector of first cluster
01070	DSKSIZ:				;Size of disk (temp used during init only)
01080	MAXCLUS:DS	2		;Number of clusters on drive + 1
01090	FATSIZ:	DS	1		;Number of records occupied by FAT
01100	FIRDIR:	DS	2		;Starting record of directory
01110	
01120		IF	SMALLDIR
01130	FIRREC1:DS	2		;First data sector with 16-byte dir. entries
01140	MAXCLUS1:DS	2		;No. of clusters + 1 with 16-byte dir. entries
01150	FIRREC2:DS	2		;First data sector with 32-byte dir. entries
01160	MAXCLUS2:DS	2		;No. of clusters + 1 with 32-byte dir entries
01170		ENDIF
01180	
01190	DIRTYFAT:DS	1		;1=FAT has been changed, -1=never been read
01200	FAT:				;Start of FAT
01210	DIRSIZ:				;-1=small dir. entry, else large
01220	
01230	
01240	; BIOS entry point defintions
01250	
01260	BIOSSEG:	EQU	60H
01270			ORG	0
01280			DS	3
01290	BIOSSTAT:	DS	3
01300	BIOSIN:		DS	3
01310	BIOSOUT:	DS	3
01320	BIOSPRINT:	DS	3
01330	BIOSAUXIN:	DS	3
01340	BIOSAUXOUT:	DS	3
01350	BIOSREAD:	DS	3
01360	BIOSWRITE:	DS	3
01370	BIOSDSKCHG:	DS	3
01380	
01390	
01400	; Location of user registers relative user stack pointer
01410	
01420		ORG	0
01430	AXSAVE:	DS	2
01440	BXSAVE:	DS	2
01450	CXSAVE:	DS	2
01460	DXSAVE:	DS	2
01470	SISAVE:	DS	2
01480	DISAVE:	DS	2
01490	BPSAVE:	DS	2
01500	DSSAVE:	DS	2
01510	ESSAVE:	DS	2
01520	IPSAVE:	DS	2
01530	CSSAVE:	DS	2
01540	FSAVE:	DS	2
01550	
01560	
01570	; Start of code
01580	
01590		ORG	0
01600		PUT	100H
01610	
01620		JMP	DOSINIT
01630	ENDDOS:	DW	ENDDOS		;SEGMENT FOR COMMAND STORED HERE
01640	ESCTAB:	
01650		DB	77		;Copy one char--RIGHT ARROW
01660		DB	59		;Copy one char--F1
01670		DB	83		;Skip one char--DELETE
01680		DB	60		;Copy to char--F2
01690		DB	62		;Skip to char--F4
01700		DB	61		;Copy line--F3
01710		DB	64		;Ctrl-Z--F6
01720		DB	63		;Reedit line (new template)--F5
01730		DB	75		;Backspace--LEFT ARROW
01740		DB	82		;Toggle insert mode--INSERT
01750		DB	65		;Escape character--F7
01760		DB	65		;End of table
01770	
01780	ESCTABLEN:EQU	$-ESCTAB
01790	
01800	
01810	QUIT:
01820		MOV	AH,0
01830		JP	SAVREGS
01840	
01850	COMMAND: ;Interrupt call entry point
01860		CMP	AH,MAXCOM
01870		JBE	SAVREGS
01880	BADCALL:
01890		MOV	AL,0
01900	IRET:	IRET
01910	
01920	ENTRY:	;System call entry point and dispatcher
01930		POP	AX		;IP from the long call at 5
01940		POP	AX		;Segment from the long call at 5
01950		SEG	CS
01960		POP	[TEMP]		;IP from the CALL 5
01970		PUSHF			;Start re-ordering the stack
01980		DI
01990		PUSH	AX		;Save segment
02000		SEG	CS
02010		PUSH	[TEMP]		;Stack now ordered as if INT had been used
02020		CMP	CL,MAXCALL	;This entry point doesn't get as many calls
02030		JA	BADCALL
02040		MOV	AH,CL
02050	SAVREGS:
02060		PUSH	ES
02070		PUSH	DS
02080		PUSH	BP
02090		PUSH	DI
02100		PUSH	SI
02110		PUSH	DX
02120		PUSH	CX
02130		PUSH	BX
02140		PUSH	AX
02150	
02160		IF	DSKTEST
02170		SEG	CS
02180		MOV	AX,[SPSAVE]
02190		SEG	CS
02200		MOV	[NSP],AX
02210		SEG	CS
02220		MOV	AX,[SSSAVE]
02230		SEG	CS
02240		MOV	[NSS],AX
02250		POP	AX
02260		PUSH	AX
02270		ENDIF
02280	
02290		SEG	CS
02300		MOV	[SPSAVE],SP
02310		SEG	CS
02320		MOV	[SSSAVE],SS
02330		MOV	SP,CS
02340		MOV	SS,SP
02350	REDISP:
02360		MOV	SP,IOSTACK
02370		EI			;Stack OK now
02380		SEG	CS
02390		MOV	[FUNC],AH
02400		MOV	BL,AH
02410		MOV	BH,0
02420		SHL	BX
02430		UP
02440		CMP	AH,12
02450		JLE	SAMSTK
02460		MOV	SP,DSKSTACK
02470	SAMSTK:
02480		SEG	CS
02490		CALL	[BX+DISPATCH]
02500	LEAVE:
02510		DI
02520		SEG	CS
02530		MOV	SP,[SPSAVE]
02540		SEG	CS
02550		MOV	SS,[SSSAVE]
02560		MOV	BP,SP
02570		MOV	[BP+AXSAVE],AL
02580	
02590		IF	DSKTEST
02600		SEG	CS
02610		MOV	AX,[NSP]
02620		SEG	CS
02630		MOV	[SPSAVE],AX
02640		SEG	CS
02650		MOV	AX,[NSS]
02660		SEG	CS
02670		MOV	[SSSAVE],AX
02680		ENDIF
02690	
02700		POP	AX
02710		POP	BX
02720		POP	CX
02730		POP	DX
02740		POP	SI
02750		POP	DI
02760		POP	BP
02770		POP	DS
02780		POP	ES
02790		IRET
02800	
02810	DISPATCH:
02820	; Standard Functions
02830		DW	ABORT
02840		DW	CONIN
02850		DW	CONOUT
02860		DW	READER
02870		DW	PUNCH
02880		DW	LIST
02890		DW	RAWIO
02900		DW	RAWINP
02910		DW	IN
02920		DW	PRTBUF
02930		DW	BUFIN
02940		DW	CONSTAT
02950		DW	FLUSHKB
02960		DW	DSKRESET
02970		DW	SELDSK
02980		DW	OPEN
02990		DW	CLOSE
03000		DW	SRCHFRST
03010		DW	SRCHNXT
03020		DW	DELETE
03030		DW	SEQRD
03040		DW	SEQWRT
03050		DW	CREATE
03060		DW	RENAME
03070		DW	INUSE
03080		DW	CURDRV
03090		DW	SETDMA
03100		DW	GETFATPT
03110		DW	WRTPROT
03120		DW	GETRDONLY
03130		DW	SETATTRIB
03140		DW	GETDSKPT
03150		DW	USERCODE
03160		DW	RNDRD
03170		DW	RNDWRT
03180		DW	FILESIZE
03190		DW	SETRNDREC
03200	; Extended Functions
03210		DW	SETVECT
03220		DW	NEWBASE
03230		DW	BLKRD
03240		DW	BLKWRT		;40
03250		DW	MAKEFCB
03260		DW	GETDATE
03270		DW	SETDATE
03280		DW	GETTIME
03290		DW	SETTIME		;45
03300	
03310	GETIO:
03320	SETIO:
03330	WRTPROT:
03340	GETRDONLY:
03350	SETATTRIB:
03360	USERCODE:
03370	INUSE:
03380	GETDSKPT:
03390		MOV	AL,0
03400		RET
03410	
03420	FLUSHKB:
03430		XOR	BX,BX
03440		MOV	ES,BX		;Select segment 0
03450		SEG	ES
03460		MOV	B,[41AH],1EH	;Reset KB queue head pointer
03470		SEG	ES
03480		MOV	B,[41CH],1EH	;Reset tail pointer
03490		MOV	AH,AL
03500		CMP	AL,1
03510		JZ	REDISPJ
03512		CMP	AL,6
03514		JZ	REDISPJ
03520		CMP	AL,7
03530		JZ	REDISPJ
03540		CMP	AL,8
03550		JZ	REDISPJ
03560		CMP	AL,10
03570		JZ	REDISPJ
03575		MOV	AL,0
03580		RET
03590	
03600	REDISPJ:JMP	REDISP
03610	
03620	READER:
03630	AUXIN:
03640		CALL	STATCHK
03650		CALL	BIOSAUXIN,BIOSSEG
03660		RET
03670	
03680	PUNCH:
03690		MOV	AL,DL
03700	AUXOUT:
03710		PUSH	AX
03720		CALL	STATCHK
03730		POP	AX
03740		CALL	BIOSAUXOUT,BIOSSEG
03750		RET
03760	
03770	
03780	UNPACK:
03790	
03800	; Inputs:
03810	;	DS = CS
03820	;	BX = Cluster number
03830	;	BP = Base of drive parameters
03840	;	SI = Pointer to drive FAT
03850	; Outputs:
03860	;	DI = Contents of FAT for given cluster
03870	;	Zero set means DI=0 (free cluster)
03880	; No other registers affected. Fatal error if cluster too big.
03890	
03900		CMP	BX,[BP+MAXCLUS]
03910		JA	HURTFAT
03920		LEA	DI,[SI+BX]
03930		SHR	BX
03940		MOV	DI,[DI+BX]
03950		JNC	HAVCLUS
03960		SHR	DI
03970		SHR	DI
03980		SHR	DI
03990		SHR	DI
04000		STC
04010	HAVCLUS:
04020		RCL	BX
04030		AND	DI,0FFFH
04040		RET
04050	
04060	HURTFAT:
04070		PUSH	AX
04080		MOV	AH,80H
04090		MOV	DI,0FFFH
04100		CALL	FATAL
04110		POP	AX
04120		RET
04130	
04140	
04150	PACK:
04160	
04170	; Inputs:
04180	;	DS = CS
04190	;	BX = Cluster number
04200	;	DX = Data
04210	;	SI = Pointer to drive FAT
04220	; Outputs:
04230	;	The data is stored in the FAT at the given cluster.
04240	;	BX,DX,DI all destroyed
04250	;	No other registers affected
04260	
04270		MOV	DI,BX
04280		SHR	BX
04290		ADD	BX,SI
04300		ADD	BX,DI
04310		SHR	DI
04320		MOV	DI,[BX]
04330		JNC	ALIGNED
04340		SHL	DX
04350		SHL	DX
04360		SHL	DX
04370		SHL	DX
04380		AND	DI,0FH
04390		JP	PACKIN
04400	ALIGNED:
04410		AND	DI,0F000H
04420	PACKIN:
04430		OR	DI,DX
04440		MOV	[BX],DI
04450		RET
04452	
04454	DEVNAME:
04455		MOV	SI,IONAME	;List of I/O devices with file names
04456		MOV	BL,6		;BL = number of device names
04457	LOOKIO:
04458		MOV	DI,NAME1
04459		MOV	CX,4		;All device names are 4 letters
04460		REPE
04461		CMPB			;Check for name in list
04462		JZ	IOCHK		;If first 4 letters OK, check the rest
04463		ADD	SI,CX		;Point to next device name
04464		DEC	BL
04465		JNZ	LOOKIO
04466	CRET:
04467		STC
04468		RET
04470	IOCHK:
04480		MOV	CX,4		;Check rest of name but not extension
04490		MOV	AL," "
04500		REPE
04510		SCAB			;Make sure rest of name is blanks
04520		JNZ	CRET
04530		MOV	AL,BL
04540		MOV	BX,IONUM-1
04550		XLAT			;Translate to internal device number
04560		MOV	BL,AL
04570		MOV	BH,-1
04580		RET
04590	
04600	GETFILE:
04610	; Same as GETNAME except ES:DI points to FCB on successful return
04620		CALL	MOVNAME
04630		JC	RET
04640		PUSH	DX
04650		PUSH	DS
04660		CALL	FINDNAME
04670		POP	ES
04680		POP	DI
04690		RET
04700	
04710	GETNAME:
04720	
04730	; Inputs:
04740	;	DS,DX point to FCB
04750	; Function:
04760	;	Find file name in disk directory. First byte is
04770	;	drive number (0=current disk). "?" matches any
04780	;	character.
04790	; Outputs:
04800	;	Carry set if file not found
04810	;	ELSE
04820	;	Zero set if attributes match (always except when creating)
04830	;	BP = Base of drive parameters
04840	;	DS = CS
04850	;	ES = CS
04860	;	BX = Pointer into directory buffer
04870	;	SI = Pointer to First Cluster field in directory entry
04880	;	[DIRBUF] has directory record with match
04890	;	[NAME1] has file name
04900	; All other registers destroyed.
04910	
04920		CALL	MOVNAME
04930		JC	RET		;Bad file name?
04940	FINDNAME:
04950		MOV	AX,CS
04960		MOV	DS,AX
04961		CALL	DEVNAME
04962		JNC	RET
05090		CALL	STARTSRCH
05100	CONTSRCH:
05110		CALL	GETENTRY
05120		JC	RET
05130	SRCH:
05140		CMP	B,[BX],0E5H
05150		JZ	NEXTENT
05160		MOV	SI,BX
05170		MOV	DI,NAME1
05180		MOV	CX,11
05190	WILDCRD:
05200		REPE
05210		CMPB
05220		JZ	FOUND
05230		CMP	B,[DI-1],"?"
05240		JZ	WILDCRD
05250	NEXTENT:
05260		CALL	NEXTENTRY
05270		JNC	SRCH
05280		RET
05290	
05300	FOUND:
05310	
05320		IF	SMALLDIR
05330		CMP	B,[BP+DIRSIZ],-1
05340		JZ	RET
05350		ENDIF
05360	
05370	;Check if attributes allow finding it
05380		MOV	AH,[ATTRIB]	;Attributes of search
05390		NOT	AH
05400		AND	AH,[SI]		;Compare with attributes of file
05410		ADD	SI,15	
05420		AND	AH,6		;Only look at bits 1 and 2
05430		JZ	RET
05440		TEST	B,[CREATING],-1
05450		JZ	NEXTENT
05460		RET
05470	
05480	
05490	GETENTRY:
05500	
05510	; Inputs:
05520	;	[LASTENT] has previously searched directory entry
05530	; Function:
05540	;	Locates next sequential directory entry in preparation for search
05550	; Outputs:
05560	;	Carry set if none
05570	;	ELSE
05580	;	AL = Current directory block
05590	;	BX = Pointer to next directory entry in [DIRBUF]
05600	;	DX = Pointer to first byte after end of DIRBUF
05610	;	[LASTENT] = New directory entry number
05620	
05630		MOV	AX,[LASTENT]
05640		INC	AX			;Start with next entry
05650		CMP	AX,[BP+MAXENT]
05660		JAE	NONE
05670	GETENT:
05680		MOV	[LASTENT],AX
05690		MOV	CL,4
05700		SHL	AX,CL
05710		XOR	DX,DX
05720	
05730		IF	SMALLDIR
05740		CMP	B,[BP+DIRSIZ],-1
05750		JZ	SMALENT1
05760		ENDIF
05770	
05780		SHL	AX
05790		RCL	DX			;Account for overflow in last shift
05800	SMALENT1:
05810		MOV	BX,[BP+SECSIZ]
05820		AND	BL,255-31		;Must be multiple of 32
05830		DIV	AX,BX
05840		MOV	BX,DX			;Position within sector
05850		MOV	AH,[BP+DRVNUM]		;AL=Directory sector no.
05860		CMP	AX,[DIRBUFID]
05870		JZ	HAVDIRBUF
05880		PUSH	BX
05890		CALL	DIRREAD
05900		POP	BX
05910	HAVDIRBUF:
05920		MOV	DX,DIRBUF
05930		ADD	BX,DX
05940		ADD	DX,[BP+SECSIZ]
05950		RET
05960	
05970	NEXTENTRY:
05980	
05990	; Inputs:
06000	;	Same as outputs of GETENTRY, above
06010	; Function:
06020	;	Update AL, BX, and [LASTENT] for next directory entry.
06030	;	Carry set if no more.
06040	
06050		MOV	DI,[LASTENT]
06060		INC	DI
06070		CMP	DI,[BP+MAXENT]
06080		JAE	NONE
06090		MOV	[LASTENT],DI
06100		ADD	BX,32
06110	
06120		IF	SMALLDIR
06130		CMP	B,[BP+DIRSIZ],-1
06140		JNZ	BIGENT3
06150		SUB	BX,16
06160	BIGENT3:
06170		ENDIF
06180	
06190		CMP	BX,DX
06200		JB	HAVIT
06210		INC	AL			;Next directory sector
06220		PUSH	DX			;Save limit
06230		CALL	DIRREAD
06240		POP	DX
06250		MOV	BX,DIRBUF
06260	HAVIT:
06270		CLC
06280		RET
06290	
06300	NONE:
06310		CALL	CHKDIRWRITE
06320		STC
06330		RET
06340	
06350	
06360	DELETE:	; System call 19
06370		CALL	GETNAME
06375		MOV	AL,-1
06380		JC	RET
06390		CMP	BH,AL		;Check if device name
06400		JZ	RET		;Can't delete I/O devices
06410	DELFILE:
06420		MOV	B,[DIRTYDIR],-1
06430		MOV	B,[BX],0E5H
06440		MOV	BX,[SI]
06450		LEA	SI,[BP+FAT]
06460		OR	BX,BX
06470		JZ	DELNXT
06480		CMP	BX,[BP+MAXCLUS]
06490		JA	DELNXT
06500		CALL	RELEASE
06510	DELNXT:
06520		CALL	CONTSRCH
06530		JNC	DELFILE
06540		CALL	FATWRT
06550		CALL	CHKDIRWRITE
06560		XOR	AL,AL
06570		RET
06580	
06590	
06600	RENAME:	;System call 23
06610		CALL	MOVNAME
06620		JC	ERRET
06650		ADD	SI,5
06660		MOV	DI,NAME2
06670		CALL	LODNAME
06675		JC	ERRET
06680		CALL	FINDNAME
06690		JC	ERRET
06692		CMP	BH,-1		;Check if I/O device name
06694		JZ	ERRET		;If so, can't rename it
06700		MOV	SI,NAME1
06710		MOV	DI,NAME3
06720		MOV	CX,6		;Include attribute byte
06730		REP
06740		MOVW			;Copy name to search for
06750	RENFIL:
06760		MOV	DI,NAME1
06770		MOV	SI,NAME2
06780		MOV	CX,11
06790	NEWNAM:
06800		LODB
06810		CMP	AL,"?"
06820		JNZ	NOCHG
06830		MOV	AL,[BX]
06840	NOCHG:
06850		STOB
06860		INC	BX
06870		LOOP	NEWNAM
06871		MOV	B,[DI],6	;Stop duplicates with any attributes
06872		CALL	DEVNAME		;Check if giving it a device name
06874		JNC	RENERR
06890		PUSH	[LASTENT]	;Save position of match
06895		MOV	[LASTENT],-1	;Search entire dirctory for duplicate
06900		CALL	CONTSRCH	;See if new name already exists
06910		POP	AX
06920		JNC	RENERR		;Error if found
06930		CALL	GETENT		;Re-read matching entry
06940		MOV	DI,BX
06950		MOV	SI,NAME1
06960		MOV	CX,11
06970		REP
06980		MOVB			;Replace old name with new
06990		MOV	B,[DIRTYDIR],-1	;Flag change in directory
07000		MOV	SI,NAME3
07010		MOV	DI,NAME1
07020		MOV	CX,6		;Include attribute byte
07030		REP
07040		MOVW			;Copy name back into search buffer
07050		CALL	CONTSRCH
07060		JNC	RENFIL
07070		CALL	CHKDIRWRITE
07080		XOR	AL,AL
07090		RET
07100	
07102	RENERR:
07104		CALL	CHKDIRWRITE
07110	ERRET:
07120		MOV	AL,-1
07130		RET
07140	
07150	
07160	MOVNAME:
07170	
07180	; Inputs:
07190	;	DS, DX point to FCB or extended FCB
07200	; Outputs:
07210	;	DS:DX point to normal FCB
07220	;	ES = CS
07230	;	If file name OK:
07240	;	BP has base of driver parameters
07250	;	[NAME1] has name in upper case
07260	; All registers except DX destroyed
07270	; Carry set if bad file name or drive
07280	
07290		SEG	CS
07300		MOV	B,[CREATING],0
07310		MOV	AX,CS
07320		MOV	ES,AX
07330		MOV	DI,NAME1
07340		MOV	SI,DX
07350		LODB
07360		SEG	CS
07370		MOV	[EXTFCB],AL
07380		MOV	AH,0
07390		CMP	AL,-1
07400		JNZ	HAVATTRB
07410		ADD	DX,7
07420		ADD	SI,6
07430		MOV	AH,[SI-1]
07440		LODB
07450	HAVATTRB:
07460		SEG	CS
07470		MOV	[ATTRIB],AH
07480		CALL	GETBP
07490		JB	RET
07500	LODNAME:
07510	; This entry point copies a file name from DS,SI
07520	; to ES,DI converting to upper case.
07522		CMP	B,[SI]," "	;First letter may not be blank
07524		STC			;Ready to indicate error
07526		JZ	RET
07530		MOV	CX,11
07540	MOVCHK:
07550		CALL	GETLET
07560		JNZ	CTRLCHK		;Is it a delimiter?
07570		CMP	AL," "		;This is the only delimiter allowed
07580		STC			;In case of error
07590		JNZ	RET
07600	CTRLCHK:
07610		CMP	AL,20H
07620		JC	RET
07630		STOB
07640		LOOP	MOVCHK
07650		RET
07660	
07670	GETBP:
07680		SEG	CS
07690		CMP	[NUMDRV],AL
07700		JC	RET
07710		CBW
07720		XCHG	BP,AX
07730		SHL	BP
07740		MOV	BP,[BP+CURDRVPT]
07750		RET
07760	
07770	
07780	OPEN:	;System call 15
07790		CALL	GETFILE
07800	DOOPEN:
07810	; Enter here to perform OPEN on file already found
07820	; in directory. DS=CS, BX points to directory
07830	; entry in DIRBUF, SI points to First Cluster field, and
07840	; ES:DI point to the FCB to be opened. This entry point
07850	; is used by CREATE.
07860		JC	ERRET
07870		CMP	BH,-1		;Check if file is I/O device
07880		JZ	OPENDEV		;Special handler if so
07890		MOV	AL,[BP+DRVNUM]
07900		INC	AL
07910		STOB
07920		ADD	DI,11		;Point to extent field
07930		XOR	AX,AX
07940		STOW			;Set extent field to 0
07950		MOV	AX,128		;Default record size
07960		STOW			;Set record size
07970		LODW			;Get starting cluster
07980		MOV	DX,AX		;Save it for the moment
07990		MOVW			;Transfer size to FCB
08000		MOVW
08010		MOV	AX,[SI-8]	;Get date
08020	
08030		IF	SMALLDIR
08040		CMP	B,[BP+DIRSIZ],-1
08050		JNZ	BIGENT10
08060		SEG	ES
08070		MOV	[DI-1],0
08080		XOR	AX,AX		;Date not available in small entry
08090	BIGENT10:
08100		ENDIF
08110	
08120		STOW			;Save date in FCB
08130		MOV	AX,[LASTENT]
08140		STOW			;directory location
08150		MOV	AX,DX		;Restore starting cluster
08160		STOW			; first cluster
08170		STOW			; last cluster accessed
08180		XOR	AX,AX
08190		STOW			; position of last cluster
08200		STOB			; dirty flag
08210		RET
08220	
08230	OPENDEV:
08240		SEG	ES
08250		MOV	[DI+FILDIRBLK],BX ;Use dir. entry number as flag
08260		XOR	AL,AL
08270		RET
08280	
08290	
08300	STARTSRCH:
08310		MOV	[LASTENT],-1
08320	FATREAD:
08330	
08340	; Inputs:
08350	;	DS = CS
08360	;	BP = Base of drive parameters
08370	; Function:
08380	;	If disk may have been changed, FAT is read in and buffers are
08390	;	flagged invalid. If not, no action is taken.
08400	; Outputs:
08410	;	AL = 0
08420	;	BP unchanged
08430	; All other registers destroyed
08440	
08450		MOV	AL,[BP+DRVNUM]
08460		CALL	BIOSDSKCHG,BIOSSEG	;See what BIOS has to say
08470		MOV	AL,[BP+DRVNUM]
08480		OR	AH,[BP+DIRTYFAT]
08490		JS	NEWDSK		;If either say new disk, then it's so
08500		DEC	AH		;Check for AH=1 (disk not changed)
08510		JZ	RET
08520		MOV	AH,1
08530		CMP	AX,[BUFDRVNO]	;Does buffer have dirty sector of this drive?
08540		JZ	RET		;If so, disk has not been changed
08550	NEWDSK:
08560		CMP	AL,[BUFDRVNO]	;See if buffer is for this drive
08570		JNZ	BUFOK		;If not, don't touch it
08580		MOV	[BUFSECNO],0	;Flag buffers invalid
08590		MOV	[BUFDRVNO],00FFH
08600	BUFOK:
08610		MOV	[DIRBUFID],-1
08620		CALL	FIGFAT
08630	NEXTFAT:
08640		PUSH	AX
08650		CALL	DSKREAD
08660		POP	AX
08670		JC	BADFAT
08680	
08690		IF	SMALLDIR
08700		MOV	DL,AL
08710		LEA	SI,[BP+FIRREC1]	;FIRREC and MAXCLUS for 16-byte dir entries
08720		CMP	B,[BP+DIRSIZ],-1
08730		JZ	SETSIZ
08740		ADD	SI,4		;FIRREC and MAXCLUS for 32-byte entries
08750	SETSIZ:
08760		LODW
08770		MOV	[BP+FIRREC],AX
08780		LODW
08790		MOV	[BP+MAXCLUS],AX
08800		MOV	AL,DL
08810		ENDIF
08820	
08830		SUB	AL,[BP+FATCNT]
08840		JZ	RET
08850		NEG	AL
08860	;{Insert error code here. AL=number of bad fats.
08870	;Since one good FAT was read, should include option
08880	;to rewrite all FATs.}
08890		JMP	FATWRT
08900	
08910	BADFAT:
08920		MOV	CX,DI
08930		ADD	DX,CX
08940		DEC	AL
08950		JNZ	NEXTFAT
08960		CALL	FIGFAT		;Reset registers
08970		JMP	DREAD		;Try first FAT once more
08980	
08990	OKRET1:
09000		MOV	AL,0
09010		RET
09020	
09030	CLOSE:	;System call 16
09040		MOV	DI,DX
09050		CMP	B,[DI],-1
09060		JNZ	NORMFCB3
09070		ADD	DI,7
09080	NORMFCB3:
09090		CMP	B,[DI+FILDIRBLK+1],-1  ;Check for I/O device
09100		JZ	OKRET1		;Can't close I/O device
09110		TEST	B,[DI+DIRTYFIL],-1
09120		JZ	OKRET1		;If not written to, do nothing
09130		MOV	AL,[DI]		;Get drive number
09140		CALL	GETBP		;Get base of drive parameters
09150		JC	BADCLOSEJ
09160		MOV	AL,[BP+DRVNUM]
09170		MOV	AH,1		;Look for dirty buffer
09180		SEG	CS
09190		CMP	AX,[BUFDRVNO]
09200		JNZ	FNDDIR
09210	;Write back dirty buffer if on same drive
09220		PUSH	DX
09230		PUSH	DS
09240		PUSH	CS
09250		POP	DS
09260		MOV	B,[DIRTYBUF],0
09270		MOV	BX,[BUFFER]
09280		MOV	CX,1
09290		MOV	DX,[BUFSECNO]
09300		CALL	DWRITE
09310		POP	DS
09320		POP	DX
09330	FNDDIR:
09340		CALL	GETFILE
09350	BADCLOSEJ:
09360		JC	BADCLOSE
09370		MOV	AX,[LASTENT]
09380		SEG	ES
09390		CMP	AX,[DI+FILDIRBLK]
09400		JNZ	BADCLOSE
09410		SEG	ES
09420		MOV	CX,[DI+FIRCLUS]
09430		MOV	[SI],CX
09440		SEG	ES
09450		MOV	DX,[DI+FILSIZ]
09460		MOV	[SI+2],DX
09470		SEG	ES
09480		MOV	DX,[DI+FILSIZ+2]
09490	
09500		IF	SMALLDIR
09510		CMP	B,[BP+DIRSIZ],-1
09520		JNZ	BIGENT11
09530		MOV	[SI+4],DL
09540		JP	SMALLENT2
09550	BIGENT11:
09560		ENDIF
09570	
09580		MOV	[SI+4],DX
09590		SEG	ES
09600		MOV	DX,[DI+FDATE]
09610		MOV	[SI-2],DX
09620	SMALLENT2:
09630		CALL	DIRWRITE
09640	
09650	CHKFATWRT:
09660	; Do FATWRT only if FAT is dirty
09670	
09680		CMP	B,[BP+DIRTYFAT],1
09690		JNZ	OKRET
09700	
09710	FATWRT:
09720	
09730	; Inputs:
09740	;	DS = CS
09750	;	BP = Base of drive parameter table
09760	; Function:
09770	;	Write the FAT back to disk and reset FAT
09780	;	dirty bit.
09790	; Outputs:
09800	;	AL = 0
09810	;	BP unchanged
09820	; All other registers destroyed
09830	
09840		MOV	B,[BP+DIRTYFAT],0
09850		CALL	FIGFAT
09860	EACHFAT:
09870		PUSH	DX
09880		PUSH	CX
09890		PUSH	BX
09900		PUSH	AX
09910		CALL	DWRITE
09920		POP	AX
09930		POP	BX
09940		POP	CX
09950		POP	DX
09960		ADD	DX,CX
09970		DEC	AL
09980		JNZ	EACHFAT
09990	OKRET:
10000		MOV	AL,0
10010		RET
10020	
10030	BADCLOSE:
10040		MOV	B,[BP+DIRTYFAT],0
10050		MOV	AL,-1
10060		RET
10070	
10080	
10090	FIGFAT:
10100	; Loads registers with values needed to read or
10110	; write a FAT.
10120		MOV	AL,[BP+FATCNT]
10130		LEA	BX,[BP+FAT]
10140		MOV	CL,[BP+FATSIZ]	;No. of records occupied by FAT
10150		MOV	CH,0
10160		MOV	DX,[BP+FIRFAT]	;Record number of start of FATs
10170		RET
10180	
10190	
10200	DIRCOMP:
10210	; Prepare registers for directory read or write
10220		CBW
10230		ADD	AX,[BP+FIRDIR]
10240		MOV	DX,AX
10250		MOV	BX,DIRBUF
10260		MOV	CX,1
10270		RET
10280	
10290	
10300	CREATE:	;System call 22
10310		CALL	MOVNAME
10320		JC	ERRET3
10330		MOV	DI,NAME1
10340		MOV	CX,11
10350		MOV	AL,"?"
10360		REPNE
10370		SCAB
10380		JZ	ERRET3
10390		SEG	CS
10400		MOV	B,[CREATING],1
10410		PUSH	DX
10420		PUSH	DS
10430		CALL	FINDNAME
10440		JNC	EXISTENT
10450		CALL	STARTSRCH
10460		CALL	GETENTRY
10470	LOOKFRE:
10480		CMP	B,[BX],0E5H
10490		JZ	FREESPOT
10500		CALL	NEXTENTRY
10510		JNC	LOOKFRE
10520	ERRPOP:
10530		POP	DS
10540		POP	DX
10550	ERRET3:
10560		MOV	AL,-1
10570		RET
10580	
10590	EXISTENT:
10600		JNZ	ERRPOP		;Error if attributes don't match
10610		CMP	BH,-1		;Check if file is I/O device
10620		JZ	OPENJMP		;If so, no action
10630		MOV	CX,[SI]		;Get pointer to clusters
10640		JCXZ	FREESPOT
10650		CMP	CX,[BP+MAXCLUS]
10660		JA	FREESPOT
10670		PUSH	BX
10680		MOV	BX,CX
10690		LEA	SI,[BP+FAT]
10700		CALL	RELEASE		;Free any data already allocated
10710		CALL	FATWRT
10720		POP	BX
10730	FREESPOT:
10740		MOV	DI,BX
10750		MOV	SI,NAME1
10760		MOV	CX,5
10770		MOVB
10780		REP
10790		MOVW
10800	
10810		IF	SMALLDIR
10820		CMP	B,[BP+DIRSIZ],-1
10830		JNZ	BIGENT4
10840		PUSH	DI
10850		MOV	CL,5
10860		XOR	AX,AX
10870		JP	SMALLENT
10880	BIGENT4:
10890		ENDIF
10900	
10910		MOV	AL,[ATTRIB]
10920		STOB
10930		XOR	AX,AX
10940		MOV	CL,6
10950		REP
10960		STOW
10970		CALL	DATE16
10980		STOW
10990		XOR	AX,AX
11000		PUSH	DI
11010		MOV	CL,6
11020	SMALLENT:
11030		REP
11040		STOB
11050		PUSH	BX
11060		CALL	DIRWRITE
11070		POP	BX
11080		POP	SI
11090	OPENJMP:
11100		CLC			;Clear carry so OPEN won't fail
11110		POP	ES
11120		POP	DI
11130		JMP	DOOPEN
11140	
11150	
11160	DIRREAD:
11170	
11180	; Inputs:
11190	;	DS = CS
11200	;	AL = Directory block number
11210	;	BP = Base of drive parameters
11220	; Function:
11230	;	Read the directory block into DIRBUF.
11240	; Outputs:
11250	;	AX,BP unchanged
11260	; All other registers destroyed.
11270	
11280		PUSH	AX
11290		CALL	CHKDIRWRITE
11300		POP	AX
11310		PUSH	AX
11320		MOV	AH,[BP+DRVNUM]
11330		MOV	[DIRBUFID],AX
11340		CALL	DIRCOMP
11350		CALL	DREAD
11360		POP	AX
11370		RET
11380	
11390	
11400	DREAD:
11410	
11420	; Inputs:
11430	;	BX,DS = Transfer address
11440	;	CX = Number of sectors
11450	;	DX = Absolute record number
11460	;	BP = Base of drive parameters
11470	; Function:
11480	;	Calls BIOS to perform disk read. If BIOS reports
11490	;	errors, will call HARDERR for further action.
11500	; BP preserved. All other registers destroyed.
11510	
11520		CALL	DSKREAD
11530		JNC	RET
11540		SEG	CS
11550		MOV	B,[READOP],0
11560		CALL	HARDERR
11570		CMP	AL,1		;Check for retry
11580		JZ	DREAD
11590		RET			;Ignore otherwise
11600	
11610	HARDERR:
11620	;Hard disk error handler. Entry conditions:
11630	;	DS:BX = Original disk transfer address
11640	;	DX = Original logical sector number
11650	;	CX = Number of sectors to go (first one gave the error)
11660	;	AX = Hardware error code
11670	;	DI = Original sector transfer count
11680	;	BP = Base of drive parameters
11690	;	[READOP] = 0 for read, 1 for write
11700	
11710		XCHG	AX,DI		;Error code in DI, count in AX
11720		SUB	AX,CX		;Number of sectors successfully transferred
11730		ADD	DX,AX		;First sector number to retry
11740		PUSH	DX
11750		MUL	AX,[BP+SECSIZ]	;Number of bytes transferred
11760		POP	DX
11770		ADD	BX,AX		;First address for retry
11780		MOV	AH,0		;Flag disk section in error
11790		CMP	DX,[BP+FIRFAT]	;In reserved area?
11800		JB	ERRINT
11810		INC	AH		;Flag for FAT
11820		CMP	DX,[FIRDIR]	;In FAT?
11830		JB	ERRINT
11840		INC	AH
11850		CMP	DX,[FIRREC]	;In directory?
11860		JB	ERRINT
11870		INC	AH		;Must be in data area
11880	ERRINT:
11890		SHL	AH		;Make room for read/write bit
11900		SEG	CS
11910		OR	AH,[READOP]
11920	FATAL:
11930		MOV	AL,[BP+DRVNUM]	;Get drive number
11940		PUSH	BP		;The only thing we preserve
11950		SEG	CS
11960		MOV	[CONTSTK],SP
11970		DI			;Prepare to play with stack
11980		SEG	CS
11990		MOV	SS,[SSSAVE]
12000		SEG	CS
12010		MOV	SP,[SPSAVE]	;User stack pointer restored
12020		INT	24H		;Fatal error interrupt vector
12030		SEG	CS
12040		MOV	[SPSAVE],SP
12050		SEG	CS
12060		MOV	[SSSAVE],SS
12070		MOV	SP,CS
12080		MOV	SS,SP
12090		SEG	CS
12100		MOV	SP,[CONTSTK]
12110		EI
12120		POP	BP
12130		CMP	AL,2
12140		JZ	ERROR
12150		RET
12160	
12170	DSKREAD:
12180		MOV	AL,[BP+DRVNUM]
12190		PUSH	BP
12200		PUSH	BX
12210		PUSH	CX
12220		PUSH	DX
12230		CALL	BIOSREAD,BIOSSEG
12240		POP	DX
12250		POP	DI
12260		POP	BX
12270		POP	BP
12280		RET
12290	
12300	
12310	CHKDIRWRITE:
12320		TEST	B,[DIRTYDIR],-1
12330		JZ	RET
12340	
12350	DIRWRITE:
12360	
12370	; Inputs:
12380	;	DS = CS
12390	;	AL = Directory block number
12400	;	BP = Base of drive parameters
12410	; Function:
12420	;	Write the directory block into DIRBUF.
12430	; Outputs:
12440	;	BP unchanged
12450	; All other registers destroyed.
12460	
12470		MOV	B,[DIRTYDIR],0
12480		MOV	AL,[DIRBUFID]
12490		CALL	DIRCOMP
12500	
12510	
12520	DWRITE:
12530	
12540	; Inputs:
12550	;	BX,DS = Transfer address
12560	;	CX = Number of sectors
12570	;	DX = Absolute record number
12580	;	BP = Base of drive parameters
12590	; Function:
12600	;	Calls BIOS to perform disk write. If BIOS reports
12610	;	errors, will call HARDERR for further action.
12620	; BP preserved. All other registers destroyed.
12630	
12640		MOV	AL,[BP+DRVNUM]
12650		PUSH	BP
12660		PUSH	BX
12670		PUSH	CX
12680		PUSH	DX
12690		CALL	BIOSWRITE,BIOSSEG
12700		POP	DX
12710		POP	DI
12720		POP	BX
12730		POP	BP
12740		JNC	RET
12750		SEG	CS
12760		MOV	B,[READOP],1
12770		CALL	HARDERR
12780		CMP	AL,1		;Check for retry
12790		JZ	DWRITE
12800		RET
12810	
12820	ABORT:
12830		SEG	CS
12840		LDS	SI,[SPSAVE]
12850		MOV	DS,[SI+CSSAVE]
12860		XOR	AX,AX
12870		MOV	ES,AX
12880		MOV	SI,SAVEXIT
12890		MOV	DI,EXIT
12900		MOVW
12910		MOVW
12920		MOVW
12930		MOVW
12940	ERROR:
12950		MOV	AX,CS
12960		MOV	DS,AX
12970		MOV	ES,AX
12980		CALL	WRTFATS
12990		XOR	AX,AX
13000		DI
13010		MOV	SS,[SSSAVE]
13020		MOV	SP,[SPSAVE]
13030		MOV	DS,AX
13040		MOV	SI,EXIT
13050		MOV	DI,EXITHOLD
13060		MOVW
13070		MOVW
13080		POP	AX
13090		POP	BX
13100		POP	CX
13110		POP	DX
13120		POP	SI
13130		POP	DI
13140		POP	BP
13150		POP	DS
13160		POP	ES
13170		EI			;Stack OK now
13180		SEG	CS
13190		JMP	L,[EXITHOLD]
13200	
13210	
13220	SEQRD:	;System call 20
13230		CALL	GETREC
13240		CALL	LOAD
13250		JP	FINSEQ
13260	
13270	SEQWRT:	;System call 21
13280		CALL	GETREC
13290		CALL	STORE
13300	FINSEQ:
13310		JCXZ	SETNREX
13320		ADD	AX,1
13330		ADC	DX,0
13340		JP	SETNREX
13350	
13360	RNDRD:	;System call 33
13370		CALL	GETRRPOS1
13380		CALL	LOAD
13390		JP	FINRND
13400	
13410	RNDWRT:	;System call 34
13420		CALL	GETRRPOS1
13430		CALL	STORE
13440		JP	FINRND
13450	
13460	BLKRD:	;System call 39
13470		CALL	GETRRPOS
13480		CALL	LOAD
13490		JP	FINBLK
13500	
13510	BLKWRT:	;System call 40
13520		CALL	GETRRPOS
13530		CALL	STORE
13540	FINBLK:
13550		LDS	SI,[SPSAVE]
13560		MOV	[SI+CXSAVE],CX
13570		JCXZ	FINRND
13580		ADD	AX,1
13590		ADC	DX,0
13600	FINRND:
13610		SEG	ES
13620		MOV	[DI+RR],AX
13630		SEG	ES
13640		MOV	[DI+RR+2],DL
13650		OR	DH,DH
13660		JZ	SETNREX
13670		SEG	ES
13680		MOV	[DI+RR+3],DH	;Save 4 byte of RECPOS only if significant
13690	SETNREX:
13700		MOV	CX,AX
13710		AND	AL,7FH
13720		SEG	ES
13730		MOV	[DI+NR],AL
13740		AND	CL,80H
13750		SHL	CX
13760		RCL	DX
13770		MOV	AL,CH
13780		MOV	AH,DL
13790		SEG	ES
13800		MOV	[DI+EXTENT],AX
13810		SEG	CS
13820		MOV	AL,[DSKERR]
13830		RET
13840	
13850	GETRRPOS1:
13860		MOV	CX,1
13870	GETRRPOS:
13880		MOV	DI,DX
13890		CMP	B,[DI],-1
13900		JNZ	NORMFCB1
13910		ADD	DI,7
13920	NORMFCB1:
13930		MOV	AX,[DI+RR]
13940		MOV	DX,[DI+RR+2]
13950		RET
13960	
13970	NOFILERR:
13980		XOR	CX,CX
13990		MOV	B,[DSKERR],4
14000		POP	BX
14010		RET
14020	
14030	SETUP:
14040	
14050	; Inputs:
14060	;	DS:DI point to FCB
14070	;	DX:AX = Record position in file of disk transfer
14080	;	CX = Record count
14090	; Outputs:
14100	;	DS = CS
14110	;	ES:DI point to FCB
14120	;	CX = No. of bytes to transfer
14130	;	BP = Base of drive parameters
14140	;	SI = FAT pointer
14150	;	[RECCNT] = Record count
14160	;	[RECPOS] = Record position in file
14170	;	[FCB] = DI
14180	;	[NEXTADD] = Displacement of disk transfer within segment
14190	;	[SECPOS] = Position of first sector
14200	;	[BYTPOS] = Byte position in file
14210	;	[BYTSECPOS] = Byte position in first sector
14220	;	[CLUSNUM] = First cluster
14230	;	[SECCLUSPOS] = Sector within first cluster
14240	;	[DSKERR] = 0 (no errors yet)
14250	;	[TRANS] = 0 (No transfers yet)
14260	; If SETUP detects no records will be transfered, it returns 1 level up 
14270	; with CX = 0.
14280	
14290		PUSH	AX
14300		MOV	AL,[DI]
14310		MOV	SI,[DI+RECSIZ]
14320		OR	SI,SI
14330		JNZ	HAVRECSIZ
14340		MOV	SI,128
14350		MOV	[DI+RECSIZ],SI
14360	HAVRECSIZ:
14370		MOV	BX,DS
14380		MOV	ES,BX
14390		MOV	BX,CS
14400		MOV	DS,BX
14410		CALL	GETBP
14420		POP	AX
14430		JC	NOFILERR
14440		CMP	SI,64		;Check if highest byte of RECPOS is significant
14450		JB	SMALREC
14460		MOV	DH,0		;Ignore MSB if record >= 64 bytes
14470	SMALREC:
14480		MOV	[RECCNT],CX
14490		MOV	[RECPOS],AX
14500		MOV	[RECPOS+2],DX
14510		MOV	[FCB],DI
14520		MOV	BX,[DMAADD]
14530		MOV	[NEXTADD],BX
14540		MOV	B,[DSKERR],0
14550		MOV	B,[TRANS],0
14560		MOV	BX,DX
14570		MUL	AX,SI
14580		MOV	[BYTPOS],AX
14590		PUSH	DX
14600		MOV	AX,BX
14610		MUL	AX,SI
14620		POP	BX
14630		ADD	AX,BX
14640		ADC	DX,0		;Ripple carry
14650		JNZ	EOFERR
14660		MOV	[BYTPOS+2],AX
14670		MOV	DX,AX
14680		MOV	AX,[BYTPOS]
14690		MOV	BX,[BP+SECSIZ]
14700		CMP	DX,BX		;See if divide will overflow
14710		JNC	EOFERR
14720		DIV	AX,BX
14730		MOV	[SECPOS],AX
14740		MOV	[BYTSECPOS],DX
14750		MOV	DX,AX
14760		AND	AL,[BP+CLUSMSK]
14770		MOV	[SECCLUSPOS],AL
14780		MOV	AX,CX		;Record count
14790		MOV	CL,[BP+CLUSSHFT]
14800		SHR	DX,CL
14810		MOV	[CLUSNUM],DX
14820		MUL	AX,SI		;Multiply by bytes per record
14830		MOV	CX,AX
14840		ADD	AX,[DMAADD]	;See if it will fit in one segment
14850		ADC	DX,0
14860		JZ	OK		;Must be less than 64K
14870		MOV	AX,[DMAADD]
14880		NEG	AX		;Amount of room left in segment
14890		JNZ	PARTSEG		;All 64K available?
14900		DEC	AX		;If so, reduce it by one
14910	PARTSEG:
14920		XOR	DX,DX
14930		DIV	AX,SI		;How many records will fit?
14940		MOV	[RECCNT],AX
14950		MUL	AX,SI		;Translate that back into bytes
14960		MOV	B,[DSKERR],2	;Flag that trimming took place
14970		MOV	CX,AX
14980		JCXZ	NOROOM
14990	OK:
15000		LEA	SI,[BP+FAT]
15010		RET
15020	
15030	EOFERR:
15040		MOV	B,[DSKERR],1
15050		XOR	CX,CX
15060	NOROOM:
15070		POP	BX		;Kill return address
15080		RET
15090	
15100	BREAKDOWN:
15110	
15120	;Inputs:
15130	;	DS = CS
15140	;	CX = Length of disk transfer in bytes
15150	;	BP = Base of drive parameters
15160	;	[BYTSECPOS] = Byte position witin first sector
15170	;Outputs:
15180	;	[BYTCNT1] = Bytes to transfer in first sector
15190	;	[SECCNT] = No. of whole sectors to transfer
15200	;	[BYTCNT2] = Bytes to transfer in last sector
15210	;AX, BX, DX destroyed. No other registers affected.
15220	
15230		MOV	AX,[BYTSECPOS]
15240		MOV	BX,CX
15250		OR	AX,AX
15260		JZ	SAVFIR		;Partial first sector?
15270		SUB	AX,[BP+SECSIZ]
15280		NEG	AX		;Max number of bytes left in first sector
15290		SUB	BX,AX		;Subtract from total length
15300		JAE	SAVFIR
15310		ADD	AX,BX		;Don't use all of the rest of the sector
15320		XOR	BX,BX		;And no bytes are left
15330	SAVFIR:
15340		MOV	[BYTCNT1],AX
15350		MOV	AX,BX
15360		XOR	DX,DX
15370		DIV	AX,[BP+SECSIZ]	;How many whole sectors?
15380		MOV	[SECCNT],AX
15390		MOV	[BYTCNT2],DX	;Bytes remaining for last sector
15400		RET
15410	
15420	
15430	FNDCLUS:
15440	
15450	; Inputs:
15460	;	DS = CS
15470	;	CX = No. of clusters to skip
15480	;	BP = Base of drive parameters
15490	;	SI = FAT pointer
15500	;	ES:DI point to FCB
15510	; Outputs:
15520	;	BX = Last cluster skipped to
15530	;	CX = No. of clusters remaining (0 unless EOF)
15540	;	DX = Position of last cluster
15550	; DI destroyed. No other registers affected.
15560	
15570		SEG	ES
15580		MOV	BX,[DI+LSTCLUS]
15590		SEG	ES
15600		MOV	DX,[DI+CLUSPOS]
15610		OR	BX,BX
15620		JZ	NOCLUS
15630		SUB	CX,DX
15640		JNB	FINDIT
15650		ADD	CX,DX
15660		XOR	DX,DX
15670		SEG	ES
15680		MOV	BX,[DI+FIRCLUS]
15690	FINDIT:
15700		JCXZ	RET
15710	SKPCLP:
15720		CALL	UNPACK
15730		CMP	DI,0FF8H
15740		JAE	RET
15750		XCHG	BX,DI
15760		INC	DX
15770		LOOP	SKPCLP
15780		RET
15790	NOCLUS:
15800		INC	CX
15810		DEC	DX
15820		RET
15830	
15840	
15850	BUFSEC:
15860	; Inputs:
15870	;	AL = 0 if buffer must be read, 1 if no pre-read needed
15880	;	BP = Base of drive parameters
15890	;	[CLUSNUM] = Physical cluster number
15900	;	[SECCLUSPOS] = Sector position of transfer within cluster
15910	;	[BYTCNT1] = Size of transfer
15920	; Function:
15930	;	Insure specified sector is in buffer, flushing buffer before
15940	;	read if necessary.
15950	; Outputs:
15960	;	SI = Pointer to buffer
15970	;	DI = Pointer to transfer address
15980	;	CX = Number of bytes
15990	;	[NEXTADD] updated
16000	;	[TRANS] set to indicate a transfer will occur
16010	
16020		MOV	DX,[CLUSNUM]
16030		MOV	BL,[SECCLUSPOS]
16040		CALL	FIGREC
16050		MOV	[PREREAD],AL
16060		CMP	DX,[BUFSECNO]
16070		JNZ	GETSEC
16080		MOV	AL,[BUFDRVNO]
16090		CMP	AL,[BP+DRVNUM]
16100		JZ	FINBUF		;Already have it?
16110	GETSEC:
16120		TEST	B,[DIRTYBUF],-1
16130		JZ	RDSEC
16140		PUSH	DX
16150		PUSH	BP
16160		MOV	BP,[BUFDRVBP]
16170		MOV	BX,[BUFFER]
16180		MOV	CX,1
16190		MOV	DX,[BUFSECNO]
16200		CALL	DWRITE
16210		POP	BP
16220		POP	DX
16230	RDSEC:
16240		TEST	B,[PREREAD],-1
16250		JNZ	SETBUF
16260		MOV	BX,[BUFFER]
16270		MOV	CX,1
16280		PUSH	DX
16290		CALL	DREAD
16300		POP	DX
16310	SETBUF:
16320		MOV	[BUFSECNO],DX
16330		MOV	AL,[BP+DRVNUM]
16340		MOV	AH,0
16350		MOV	[BUFDRVNO],AX
16360		MOV	[BUFDRVBP],BP
16370	FINBUF:
16380		MOV	B,[TRANS],1	;A transfer is taking place
16390		MOV	DI,[NEXTADD]
16400		MOV	SI,DI
16410		MOV	CX,[BYTCNT1]
16420		ADD	SI,CX
16430		MOV	[NEXTADD],SI
16440		MOV	SI,[BUFFER]
16450		ADD	SI,[BYTSECPOS]
16460		RET
16470	
16480	BUFRD:
16490		XOR	AL,AL		;Pre-read necessary
16500		CALL	BUFSEC
16510		PUSH	ES
16520		MOV	ES,[DMAADD+2]
16530		SHR	CX
16540		JNC	EVENRD
16550		MOVB
16560	EVENRD:
16570		REP
16580		MOVW
16590		POP	ES
16600		RET
16610	
16620	BUFWRT:
16630		MOV	AX,[SECPOS]
16640		INC	AX		;Set for next sector
16650		MOV	[SECPOS],AX
16660		CMP	AX,[VALSEC]	;Has sector been written before?
16670		MOV	AL,1
16680		JA	NOREAD		;Skip preread if SECPOS>VALSEC
16690		MOV	AL,0
16700	NOREAD:
16710		CALL	BUFSEC
16720		XCHG	DI,SI
16730		PUSH	DS
16740		PUSH	ES
16750		PUSH	CS
16760		POP	ES
16770		MOV	DS,[DMAADD+2]
16780		SHR	CX
16790		JNC	EVENWRT
16800		MOVB
16810	EVENWRT:
16820		REP
16830		MOVW
16840		POP	ES
16850		POP	DS
16860		MOV	B,[DIRTYBUF],1
16870		RET
16880	
16890	NEXTSEC:
16900		TEST	B,[TRANS],-1
16910		JZ	CLRET
16920		MOV	AL,[SECCLUSPOS]
16930		INC	AL
16940		CMP	AL,[BP+CLUSMSK]
16950		JBE	SAVPOS
16960		MOV	BX,[CLUSNUM]
16970		CMP	BX,0FF8H
16980		JAE	NONEXT
16990		LEA	SI,[BP+FAT]
17000		CALL	UNPACK
17010		MOV	[CLUSNUM],DI
17020		INC	[LASTPOS]
17030		MOV	AL,0
17040	SAVPOS:
17050		MOV	[SECCLUSPOS],AL
17060	CLRET:
17070		CLC
17080		RET
17090	NONEXT:
17100		STC
17110		RET
17120	
17130	TRANBUF:
17140		LODB
17150		STOB
17160		CMP	AL,13		;Check for carriage return
17170		JNZ	NORMCH
17180		MOV	B,[SI],10
17190	NORMCH:
17200		CMP	AL,10
17210		LOOPNZ	TRANBUF
17220		JNZ	ENDRDCON
17230		CALL	OUT		;Transmit linefeed
17240		XOR	SI,SI
17250		OR	CX,CX
17260		JNZ	GETBUF
17270		OR	AL,1		;Clear zero flag--not end of file
17280	ENDRDCON:
17290		MOV	[CONTPOS],SI
17300	ENDRDDEV:
17310		MOV	[NEXTADD],DI
17320		POP	ES
17330		JNZ	SETFCBJ		;Zero set if Ctrl-Z found in input
17340		MOV	DI,[FCB]
17350		SEG	ES
17360		OR	B,[DI+FILDIRBLK],80H	;Mark as no more data available
17370	SETFCBJ:
17380		JMP	SETFCB
17390	
17400	READDEV:
17410		PUSH	ES
17420		LES	DI,[DMAADD]
17430		OR	BL,BL
17440		JZ	READCON
17450		DEC	BL
17460		JNZ	ENDRDDEV
17470	READAUX:
17480		CALL	AUXIN
17490		STOB
17500		CMP	AL,1AH
17510		LOOPNZ	READAUX
17520		JP	ENDRDDEV
17530	
17540	READCON:
17550		PUSH	CS
17560		POP	DS
17570		MOV	SI,[CONTPOS]
17580		OR	SI,SI
17590		JNZ	TRANBUF
17600		CMP	B,[CONBUF],128
17610		JZ	GETBUF
17620		MOV	[CONBUF],0FF80H	;Set up 128-byte buffer with no template
17630	GETBUF:
17640		PUSH	CX
17650		PUSH	ES
17660		PUSH	DI
17670		MOV	DX,CONBUF
17680		CALL	BUFIN		;Get input buffer
17690		POP	DI
17700		POP	ES
17710		POP	CX
17720		MOV	SI,CONBUF+2
17730		CMP	B,[SI],1AH	;Check for Ctrl-Z in first character
17740		JNZ	TRANBUF
17750		MOV	AL,1AH
17760		STOB
17770		MOV	AL,10
17780		CALL	OUT		;Send linefeed
17790		XOR	SI,SI
17800		JP	ENDRDCON
17810	
17820	RDERR:
17830		XOR	CX,CX
17840		JMP	WRTERR
17850	
17860	RDLASTJ:JMP	RDLAST
17870	
17880	LOAD:
17890	
17900	; Inputs:
17910	;	DS:DI point to FCB
17920	;	DX:AX = Position in file to read
17930	;	CX = No. of records to read
17940	; Outputs:
17950	;	DX:AX = Position of last record read
17960	;	CX = No. of bytes read
17970	;	ES:DI point to FCB
17980	;	LSTCLUS, CLUSPOS fields in FCB set
17990	
18000		CALL	SETUP
18010		SEG	ES
18020		MOV	BX,[DI+FILDIRBLK]
18030		CMP	BH,-1		;Check for named device I/O
18040		JZ	READDEV
18050		SEG	ES
18060		MOV	AX,[DI+FILSIZ]
18070		SEG	ES
18080		MOV	BX,[DI+FILSIZ+2]
18090		SUB	AX,[BYTPOS]
18100		SBC	BX,[BYTPOS+2]
18110		JB	RDERR
18120		JNZ	ENUF
18130		OR	AX,AX
18140		JZ	RDERR
18150		CMP	AX,CX
18160		JAE	ENUF
18170		MOV	CX,AX
18180	ENUF:
18190		CALL	BREAKDOWN
18200		MOV	CX,[CLUSNUM]
18210		CALL	FNDCLUS
18220		OR	CX,CX
18230		JNZ	RDERR
18240		MOV	[LASTPOS],DX
18250		MOV	[CLUSNUM],BX
18260		CMP	[BYTCNT1],0
18270		JZ	RDMID
18280		CALL	BUFRD
18290	RDMID:
18300		CMP	[SECCNT],0
18310		JZ	RDLASTJ
18320		CALL	NEXTSEC
18330		JC	SETFCB
18340		MOV	B,[TRANS],1	;A transfer is taking place
18350	ONSEC:
18360		MOV	DL,[SECCLUSPOS]
18370		MOV	CX,[SECCNT]
18380		MOV	BX,[CLUSNUM]
18390	RDLP:
18400		CALL	OPTIMIZE
18410		PUSH	DI
18420		PUSH	AX
18430		PUSH	DS
18440		MOV	DS,[DMAADD+2]
18450		CALL	DREAD
18460		POP	DS
18470		POP	CX
18480		POP	BX
18490		JCXZ	RDLAST
18500		CMP	BX,0FF8H
18510		JAE	SETFCB
18520		MOV	DL,0
18530		INC	[LASTPOS]	;We'll be using next cluster
18540		JP	RDLP
18550	
18560	SETFCB:
18570		MOV	SI,[FCB]
18580		MOV	AX,[NEXTADD]
18590		MOV	DI,AX
18600		SUB	AX,[DMAADD]	;Number of bytes transfered
18610		XOR	DX,DX
18620		SEG	ES
18630		MOV	CX,[SI+RECSIZ]
18640		DIV	AX,CX		;Number of records
18650		CMP	AX,[RECCNT]	;Check if all records transferred
18660		JZ	FULLREC
18670		MOV	B,[DSKERR],1
18680		OR	DX,DX
18690		JZ	FULLREC		;If remainder 0, then full record transfered
18700		MOV	B,[DSKERR],3	;Flag partial last record
18710		SUB	CX,DX		;Bytes left in last record
18720		PUSH	ES
18730		MOV	ES,[DMAADD+2]
18740		XCHG	AX,BX		;Save the record count temporarily
18750		XOR	AX,AX		;Fill with zeros
18760		SHR	CX
18770		JNC	EVENFIL
18780		STOB
18790	EVENFIL:
18800		REP
18810		STOW
18820		XCHG	AX,BX		;Restore record count to AX
18830		POP	ES
18840		INC	AX		;Add last (partial) record to total
18850	FULLREC:
18860		MOV	CX,AX
18870		MOV	DI,SI		;ES:DI point to FCB
18880	SETCLUS:
18890		MOV	AX,[CLUSNUM]
18900		SEG	ES
18910		MOV	[DI+LSTCLUS],AX
18920		MOV	AX,[LASTPOS]
18930		SEG	ES
18940		MOV	[DI+CLUSPOS],AX
18950	ADDREC:
18960		MOV	AX,[RECPOS]
18970		MOV	DX,[RECPOS+2]
18975		JCXZ	RET		;If no records read, don't change pos.
18980		DEC	CX
18990		ADD	AX,CX		;Update current record position
19000		ADC	DX,0
19010		INC	CX	
19020		RET
19030	
19040	RDLAST:
19050		MOV	AX,[BYTCNT2]
19060		OR	AX,AX
19070		JZ	SETFCB
19080		MOV	[BYTCNT1],AX
19090		CALL	NEXTSEC
19100		JC	SETFCB
19110		MOV	[BYTSECPOS],0
19120		CALL	BUFRD
19130		JP	SETFCB
19140	
19150	WRTDEV:
19160		PUSH	DS
19170		LDS	SI,[DMAADD]
19180		AND	BL,7FH
19190		OR	BL,BL
19200		JZ	WRTCON
19210		DEC	BL
19220		JZ	WRTAUX
19230		DEC	BL
19240		JNZ	ENDWRDEV	;Done if device is NUL
19250	WRTLST:
19260		LODB
19270		CMP	AL,1AH
19280		JZ	ENDWRDEV
19290		CALL	LISTOUT
19300		LOOP	WRTLST
19310		JP	ENDWRDEV
19320	
19330	WRTAUX:
19340		LODB
19350		CALL	AUXOUT
19360		CMP	AL,1AH
19370		LOOPNZ	WRTAUX
19380		JP	ENDWRDEV
19390	
19400	WRTCON:
19410		LODB
19420		CMP	AL,1AH
19430		JZ	ENDWRDEV
19440		CALL	OUT
19450		LOOP	WRTCON
19460	ENDWRDEV:
19470		POP	DS
19480		MOV	CX,[RECCNT]
19490		MOV	DI,[FCB]
19500		JP	ADDREC
19510	
19520	HAVSTART:
19530		MOV	CX,AX
19540		CALL	SKPCLP
19550		JCXZ	DOWRTJ
19560		CALL	ALLOCATE
19570		JNC	DOWRTJ
19580	WRTERR:
19590		MOV	B,[DSKERR],1
19600	LVDSK:
19610		MOV	AX,[RECPOS]
19620		MOV	DX,[RECPOS+2]
19630		MOV	DI,[FCB]
19640		RET
19650	
19660	DOWRTJ:	JMP	DOWRT
19670	
19680	WRTEOFJ:
19690		JMP	WRTEOF
19700	
19710	STORE:
19720	
19730	; Inputs:
19740	;	DS:DI point to FCB
19750	;	DX:AX = Position in file of disk transfer
19760	;	CX = Record count
19770	; Outputs:
19780	;	DX:AX = Position of last record written
19790	;	CX = No. of records written
19800	;	ES:DI point to FCB
19810	;	LSTCLUS, CLUSPOS fields in FCB set
19820	
19830		MOV	B,[DI+DIRTYFIL],1
19840		CALL	SETUP
19850		CALL	DATE16
19860		SEG	ES
19870		MOV	[DI+FDATE],AX
19880		SEG	ES
19890		MOV	BX,[DI+FILDIRBLK]
19900		CMP	BH,-1
19910		JZ	WRTDEV
19920		CALL	BREAKDOWN
19930		MOV	AX,[BYTPOS]
19940		MOV	DX,[BYTPOS+2]
19950		JCXZ	WRTEOFJ
19960		DEC	CX
19970		ADD	AX,CX
19980		ADC	DX,0		;AX:DX=last byte accessed
19990		DIV	AX,[BP+SECSIZ]	;AX=last sector accessed
20000		MOV	CL,[BP+CLUSSHFT]
20010		SHR	AX,CL		;Last cluster to be accessed
20020		PUSH	AX
20030		SEG	ES
20040		MOV	AX,[DI+FILSIZ]
20050		SEG	ES
20060		MOV	DX,[DI+FILSIZ+2]
20070		DIV	AX,[BP+SECSIZ]
20080		OR	DX,DX
20090		JZ	NORNDUP
20100		INC	AX		;Round up if any remainder
20110	NORNDUP:
20120		MOV	[VALSEC],AX	;Number of sectors that have been written
20130		POP	AX
20140		MOV	CX,[CLUSNUM]	;First cluster accessed
20150		CALL	FNDCLUS
20160		MOV	[CLUSNUM],BX
20170		MOV	[LASTPOS],DX
20180		SUB	AX,DX		;Last cluster minus current cluster
20190		JZ	DOWRT		;If we have last clus, we must have first
20200		JCXZ	HAVSTART	;See if no more data
20210		PUSH	CX		;No. of clusters short of first
20220		MOV	CX,AX
20230		CALL	ALLOCATE
20240		POP	AX
20250		JC	WRTERR
20260		MOV	CX,AX
20270		MOV	DX,[LASTPOS]
20280		INC	DX
20290		DEC	CX
20300		JZ	NOSKIP
20310		CALL	SKPCLP
20320	NOSKIP:
20330		MOV	[CLUSNUM],BX
20340		MOV	[LASTPOS],DX
20350	DOWRT:
20360		CMP	[BYTCNT1],0
20370		JZ	WRTMID
20380		MOV	BX,[CLUSNUM]
20390		CALL	BUFWRT	
20400	WRTMID:
20410		MOV	AX,[SECCNT]
20420		OR	AX,AX
20430		JZ	WRTLAST
20440		ADD	[SECPOS],AX
20450		CALL	NEXTSEC
20460		MOV	B,[TRANS],1	;A transfer is taking place
20470		MOV	DL,[SECCLUSPOS]
20480		MOV	BX,[CLUSNUM]
20490		MOV	CX,[SECCNT]
20500	WRTLP:
20510		CALL	OPTIMIZE
20520		PUSH	DI
20530		PUSH	AX
20540		PUSH	DS
20550		MOV	DS,[DMAADD+2]
20560		CALL	DWRITE
20570		POP	DS
20580		POP	CX
20590		POP	BX
20600		JCXZ	WRTLAST
20610		MOV	DL,0
20620		INC	[LASTPOS]	;We'll be using next cluster
20630		JP	WRTLP
20640	WRTLAST:
20650		MOV	AX,[BYTCNT2]
20660		OR	AX,AX
20670		JZ	FINWRT
20680		MOV	[BYTCNT1],AX
20690		CALL	NEXTSEC
20700		MOV	[BYTSECPOS],0
20710		CALL	BUFWRT
20720	FINWRT:
20730		MOV	AX,[NEXTADD]
20740		SUB	AX,[DMAADD]
20750		ADD	AX,[BYTPOS]
20760		MOV	DX,[BYTPOS+2]
20770		ADC	DX,0
20780		MOV	CX,DX
20790		MOV	DI,[FCB]
20800		SEG	ES
20810		CMP	AX,[DI+FILSIZ]
20820		SEG	ES
20830		SBB	CX,[DI+FILSIZ+2]
20840		JB	SAMSIZ
20850		SEG	ES
20860		MOV	[DI+FILSIZ],AX
20870		SEG	ES
20880		MOV	[DI+FILSIZ+2],DX
20890	SAMSIZ:
20900		MOV	CX,[RECCNT]
20910		JMP	SETCLUS
20920	
20930	
20940	WRTERRJ:JMP	WRTERR
20950	
20960	WRTEOF:
20970		MOV	CX,AX
20980		OR	CX,DX
20990		JZ	KILLFIL
21000		SUB	AX,1
21010		SBC	DX,0
21020		DIV	AX,[BP+SECSIZ]
21030		MOV	CL,[BP+CLUSSHFT]
21040		SHR	AX,CL
21050		MOV	CX,AX
21060		CALL	FNDCLUS
21070		JCXZ	RELFILE
21080		CALL	ALLOCATE
21090		JC	WRTERRJ
21100	UPDATE:
21110		MOV	DI,[FCB]
21120		MOV	AX,[BYTPOS]
21130		SEG	ES
21140		MOV	[DI+FILSIZ],AX
21150		MOV	AX,[BYTPOS+2]
21160		SEG	ES
21170		MOV	[DI+FILSIZ+2],AX
21180		XOR	CX,CX
21190		RET
21200	
21210	RELFILE:
21220		MOV	DX,0FFFH
21230		CALL	RELBLKS
21240	SETDIRT:
21250		MOV	B,[BP+DIRTYFAT],1
21260		JP	UPDATE
21270	
21280	KILLFIL:
21290		XOR	BX,BX
21300		SEG	ES
21310		XCHG	BX,[DI+FIRCLUS]
21320		OR	BX,BX
21330		JZ	UPDATE
21340		CALL	RELEASE
21350		JP	SETDIRT
21360	
21370	
21380	OPTIMIZE:
21390	
21400	; Inputs:
21410	;	DS = CS
21420	;	BX = Physical cluster
21430	;	CX = No. of records
21440	;	DL = sector within cluster
21450	;	BP = Base of drives parameters
21460	;	[NEXTADD] = transfer address
21470	; Outputs:
21480	;	AX = No. of records remaining
21490	;	BX = Transfer address
21500	;	CX = No. or records to be transferred
21510	;	DX = Physical sector address
21520	;	DI = Next cluster
21530	;	[CLUSNUM] = Last cluster accessed
21540	;	[NEXTADD] updated
21550	; BP unchanged. Note that segment of transfer not set.
21560	
21570		PUSH	DX
21580		PUSH	BX
21590		MOV	AL,[BP+CLUSMSK]
21600		INC	AL		;Number of sectors per cluster
21610		MOV	AH,AL
21620		SUB	AL,DL		;AL = Number of sectors left in first cluster
21630		MOV	DX,CX
21640		LEA	SI,[BP+FAT]
21650		MOV	CX,0
21660	OPTCLUS:
21670	;AL has number of sectors available in current cluster
21680	;AH has number of sectors available in next cluster
21690	;BX has current physical cluster
21700	;CX has number of sequential sectors found so far
21710	;DX has number of sectors left to transfer
21720	;SI has FAT pointer
21730		CALL	UNPACK
21740		ADD	CL,AL
21750		ADC	CH,0
21760		CMP	CX,DX
21770		JAE	BLKDON
21780		MOV	AL,AH
21790		INC	BX
21800		CMP	DI,BX
21810		JZ	OPTCLUS
21820		DEC	BX
21830	FINCLUS:
21840		MOV	[CLUSNUM],BX	;Last cluster accessed
21850		SUB	DX,CX		;Number of sectors still needed
21860		PUSH	DX
21870		MOV	AX,CX
21880		MUL	AX,[BP+SECSIZ]	;Number of sectors times sector size
21890		MOV	SI,[NEXTADD]
21900		ADD	AX,SI		;Adjust by size of transfer
21910		MOV	[NEXTADD],AX
21920		POP	AX		;Number of sectors still needed
21930		POP	DX		;Starting cluster
21940		SUB	BX,DX		;Number of new clusters accessed
21950		ADD	[LASTPOS],BX
21960		POP	BX		;BL = sector postion within cluster
21970		CALL	FIGREC
21980		MOV	BX,SI
21990		RET
22000	BLKDON:
22010		SUB	CX,DX		;Number of sectors in cluster we don't want
22020		SUB	AH,CL		;Number of sectors in cluster we accepted
22030		DEC	AH		;Adjust to mean position within cluster
22040		MOV	[SECCLUSPOS],AH
22050		MOV	CX,DX		;Anyway, make the total equal to the request
22060		JP	FINCLUS
22070	
22080	
22090	FIGREC:
22100	
22110	;Inputs:
22120	;	DX = Physical cluster number
22130	;	BL = Sector postion within cluster
22140	;	BP = Base of drive parameters
22150	;Outputs:
22160	;	DX = physical sector number
22170	;No other registers affected.
22180	
22190		PUSH	CX
22200		MOV	CL,[BP+CLUSSHFT]
22210		DEC	DX
22220		DEC	DX
22230		SHL	DX,CL
22240		OR	DL,BL
22250		ADD	DX,[BP+FIRREC]
22260		POP	CX
22270		RET
22280	
22290	GETREC:
22300	
22310	; Inputs:
22320	;	DS:DX point to FCB
22330	; Outputs:
22340	;	CX = 1
22350	;	DX:AX = Record number determined by EXTENT and NR fields
22360	;	DS:DI point to FCB
22370	; No other registers affected.
22380	
22390		MOV	DI,DX
22400		CMP	B,[DI],-1
22410		JNZ	NORMFCB2
22420		ADD	DI,7
22430	NORMFCB2:
22440		MOV	CX,1
22450		MOV	AL,[DI+NR]
22460		MOV	DX,[DI+EXTENT]
22470		SHL	AL
22480		SHR	DX
22490		RCR	AL
22500		MOV	AH,DL
22510		MOV	DL,DH
22520		MOV	DH,0
22530		RET
22540	
22550	
22560	ALLOCATE:
22570	
22580	; Inputs:
22590	;	DS = CS
22600	;	ES = Segment of FCB
22610	;	BX = Last cluster of file (0 if null file)
22620	;	CX = No. of clusters to allocate
22630	;	DX = Position of cluster BX
22640	;	BP = Base of drive parameters
22650	;	SI = FAT pointer
22660	;	[FCB] = Displacement of FCB within segment
22670	; Outputs:
22680	;	IF insufficient space
22690	;	  THEN
22700	;	Carry set
22710	;	CX = max. no. of records that could be added to file
22720	;	  ELSE
22730	;	Carry clear
22740	;	BX = First cluster allocated
22750	;	FAT is fully updated including dirty bit
22760	;	FIRCLUS field of FCB set if file was null
22770	; SI,BP unchanged. All other registers destroyed.
22780	
22790		PUSH	[SI]
22800		PUSH	DX
22810		PUSH	CX
22820		PUSH	BX
22830		MOV	AX,BX
22840	ALLOC:
22850		MOV	DX,BX
22860	FINDFRE:
22870		INC	BX
22880		CMP	BX,[BP+MAXCLUS]
22890		JLE	TRYOUT
22900		CMP	AX,1
22910		JG	TRYIN
22920		POP	BX
22930		MOV	DX,0FFFH
22940		CALL	RELBLKS
22950		POP	AX		;No. of clusters requested
22960		SUB	AX,CX		;AX=No. of clusters allocated
22970		POP	DX
22980		POP	[SI]
22990		INC	DX		;Position of first cluster allocated
23000		ADD	AX,DX		;AX=max no. of cluster in file
23010		MOV	DL,[BP+CLUSMSK]
23020		MOV	DH,0
23030		INC	DX		;DX=records/cluster
23040		MUL	AX,DX		;AX=max no. of records in file
23050		MOV	CX,AX
23060		SUB	CX,[RECPOS]	;CX=max no. of records that could be written
23070		JA	MAXREC
23080		XOR	CX,CX		;If CX was negative, zero it
23090	MAXREC:
23100		STC
23110		RET
23120	
23130	TRYOUT:
23140		CALL	UNPACK
23150		JZ	HAVFRE
23160	TRYIN:
23170		DEC	AX
23180		JLE	FINDFRE
23190		XCHG	AX,BX
23200		CALL	UNPACK
23210		JZ	HAVFRE
23220		XCHG	AX,BX
23230		JP	FINDFRE
23240	HAVFRE:
23250		XCHG	BX,DX
23260		MOV	AX,DX
23270		CALL	PACK
23280		MOV	BX,AX
23290		LOOP	ALLOC
23300		MOV	DX,0FFFH
23310		CALL	PACK
23320		MOV	B,[BP+DIRTYFAT],1
23330		POP	BX
23340		POP	CX		;Don't need this stuff since we're successful
23350		POP	DX
23360		CALL	UNPACK
23370		POP	[SI]
23380		XCHG	BX,DI
23390		OR	DI,DI
23400		JNZ	RET
23410		MOV	DI,[FCB]
23420		SEG	ES
23430		MOV	[DI+FIRCLUS],BX
23440		RET
23450	
23460	
23470	RELEASE:
23480	
23490	; Inputs:
23500	;	DS = CS
23510	;	BX = Cluster in file
23520	;	SI = FAT pointer
23530	;	BP = Base of drive parameters
23540	; Function:
23550	;	Frees cluster chain starting with [BX]
23560	; AX,BX,DX,DI all destroyed. Other registers unchanged.
23570	
23580		XOR	DX,DX
23590	RELBLKS:
23600	; Enter here with DX=0FFFH to put an end-of-file mark
23610	; in the first cluster and free the rest in the chain.
23620		CALL	UNPACK
23630		JZ	RET
23640		MOV	AX,DI
23650		CALL	PACK
23660		CMP	AX,0FF8H
23670		MOV	BX,AX
23680		JB	RELEASE
23690		RET
23700	
23710	
23720	GETEOF:
23730	
23740	; Inputs:
23750	;	BX = Cluster in a file
23760	;	SI = Base of drive FAT
23770	;	DS = CS
23780	; Outputs:
23790	;	BX = Last cluster in the file
23800	; DI destroyed. No other registers affected.
23810	
23820		CALL	UNPACK
23830		CMP	DI,0FF8H
23840		JAE	RET
23850		MOV	BX,DI
23860		JP	GETEOF
23870	
23880	
23890	SRCHFRST: ;System call 17
23900		CALL	GETFILE
23910	SAVPLCE:
23920	; Search-for-next enters here to save place and report
23930	; findings.
23940		JC	KILLSRCH
23950		CMP	BH,-1
23960		JZ	SRCHDEV
23970		MOV	AX,[LASTENT]
23980		SEG	ES
23990		MOV	[DI+FILDIRBLK],AX
24000	;Information in directory entry must be copied into the first
24010	; 33 bytes starting at the disk transfer address.
24020		MOV	SI,BX
24030		LES	DI,[DMAADD]
24040		MOV	AX,00FFH
24050		CMP	AL,[EXTFCB]
24060		JNZ	NORMFCB
24070		STOW
24080		INC	AL
24090		STOW
24100		STOW
24110		MOV	AL,[ATTRIB]
24120		STOB
24130	NORMFCB:
24140		MOV	AL,[BP+DRVNUM]
24150		INC	AL
24160		STOB		;Set drive number
24170		MOVB		;Copy first character of name
24180		MOV	CX,5
24190		REP
24200		MOVW		;Copy remaining 10 characters of name
24210		XOR	AX,AX
24220	
24230		IF	SMALLDIR
24240		CMP	B,[BP+DIRSIZ],-1
24250		JNZ	BIGENT5
24260		STOB		;Zero out unused portion
24270		MOV	CX,7
24280		REP
24290		STOW		;Zero a total of 15 bytes
24300		MOVW		;Copy first cluster pointer
24310		MOVW		;Copy low word of length
24320		MOVB		;Copy 3rd byte of length
24330		STOB		;4th byte of length must be zero
24340		RET
24350	BIGENT5:
24360		ENDIF
24370	
24380		MOV	CX,10
24390		REP
24400		MOVW
24410		MOVB
24420		RET
24430	
24440	KILLSRCH:
24450		SEG	ES
24460	KILLSRCH1:
24470		MOV	[DI+FILDIRBLK],-2
24480		MOV	AL,-1
24490		RET
24500	
24510	SRCHDEV:
24520		SEG	ES
24530		MOV	[DI+FILDIRBLK],BX
24540		LES	DI,[DMAADD]
24550		XOR	AX,AX
24560		STOB			;Zero drive byte
24570		SUB	SI,4		;Point to device name
24580		MOVW
24590		MOVW
24600		MOV	AX,2020H
24610		MOV	CX,3
24620		REP
24630		STOW			;Fill with 6 blanks
24640		STOB			;And a 7th
24650		XOR	AX,AX
24660		MOV	CX,10
24670		REP
24680		STOW
24690		STOB
24700		RET
24710	
24720	SRCHNXT: ;System call 18
24730		CALL	MOVNAME
24740		MOV	DI,DX
24750		JC	KILLSRCH1
24760		PUSH	DX
24770		PUSH	DS
24780		MOV	AX,[DI+FILDIRBLK]
24790		PUSH	CS
24800		POP	DS
24810		MOV	[LASTENT],AX
24820		CALL	CONTSRCH
24830		POP	ES
24840		POP	DI
24850		JMP	SAVPLCE
24860	
24870	
24880	FILESIZE: ;System call 35
24890		CALL	GETFILE
24900		MOV	AL,-1
24910		JC	RET
24920		ADD	DI,33		;Write size in RR field
24930		SEG	ES
24940		MOV	CX,[DI-33+RECSIZ]
24950		OR	CX,CX
24960		JNZ	RECOK
24970		MOV	CX,128
24980	RECOK:
24990		XOR	AX,AX
25000		XOR	DX,DX		;Intialize size to zero
25010		CMP	BH,-1		;Check for named I/O device
25020		JZ	DEVSIZ
25030		INC	SI
25040		INC	SI		;Point to length field
25050		MOV	AX,[SI+2]	;Get high word of size
25060	
25070		IF	SMALLDIR
25080		CMP	B,[BP+DIRSIZ],-1
25090		JNZ	BIGSIZ
25100		MOV	AH,0
25110	BIGSIZ:
25120		ENDIF
25130	
25140		DIV	AX,CX
25150		PUSH	AX		;Save high part of result
25160		LODW			;Get low word of size
25170		DIV	AX,CX
25180		OR	DX,DX		;Check for zero remainder
25190		POP	DX
25200		JZ	DEVSIZ
25210		INC	AX		;Round up for partial record
25220		JNZ	DEVSIZ		;Propagate carry?
25230		INC	DX
25240	DEVSIZ:
25250		STOW
25260		MOV	AX,DX
25270		STOB
25280		MOV	AL,0
25290		CMP	CX,64
25300		JAE	RET		;Only 3-byte field if RECSIZ >= 64
25310		SEG	ES
25320		MOV	[DI],AH
25330		RET
25340	
25350	
25360	SETDMA:	;System call 26
25370		SEG	CS
25380		MOV	[DMAADD],DX
25390		SEG	CS
25400		MOV	[DMAADD+2],DS
25410		RET
25420	
25430	
25440	GETFATPT: ;System call 27
25450		MOV	AX,CS
25460		MOV	DS,AX
25470		MOV	BP,[CURDRVPT]
25480		CALL	FATREAD
25490		LEA	BX,[BP+FAT]
25500		MOV	AL,[BP+CLUSMSK]
25510		INC	AL
25520		MOV	DX,[BP+MAXCLUS]
25530		DEC	DX
25540		MOV	B,[BP+DIRTYFAT],1
25550		MOV	CX,[BP+SECSIZ]
25560		LDS	SI,[SPSAVE]
25570		MOV	[SI+BXSAVE],BX
25580		MOV	[SI+DXSAVE],DX
25590		MOV	[SI+CXSAVE],CX
25600		MOV	[SI+DSSAVE],CS
25610		RET
25620	
25630	
25640	DSKRESET: ;System call 13
25650		SEG	CS
25660		MOV	[DMAADD+2],DS
25670		MOV	AX,CS
25680		MOV	DS,AX
25690		MOV	[DMAADD],80H
25700		MOV	AX,[CURDRVPT+2]
25710		MOV	[CURDRVPT],AX
25720	WRTFATS:
25730	; DS=CS. Writes back all dirty FATs. All registers destroyed.
25740		MOV	AX,[BUFDRVNO]
25750		OR	AH,AH
25760		JZ	NOBUF
25770		CBW
25780		MOV	BX,AX
25790		SHL	BX
25800		MOV	BP,[BX+DRVTAB]
25810		MOV	B,[DIRTYBUF],0
25820		MOV	DX,[BUFSECNO]
25830		MOV	BX,BUFFER
25840		MOV	CX,1
25850		CALL	DWRITE
25860	NOBUF:
25870		MOV	CL,[NUMDRV]
25880		MOV	CH,0
25890		MOV	SI,CURDRVPT+2
25900	WRTFAT:
25910		LODW
25920		PUSH	CX
25930		PUSH	SI
25940		MOV	BP,AX
25950		CALL	CHKFATWRT
25960		POP	SI
25970		POP	CX
25980		LOOP	WRTFAT
25990		RET
26000	
26010	
26020	CURDRV:	;System call 25
26030		SEG	CS
26040		MOV	BP,[CURDRVPT]
26050		MOV	AL,[BP+DRVNUM]
26060		RET
26070	
26080	
26090	SETRNDREC: ;System call 36
26100		CALL	GETREC
26110		MOV	[DI+33],AX
26120		MOV	[DI+35],DL
26130		CMP	[DI+RECSIZ],64
26140		JAE	RET
26150		MOV	[DI+36],DH	;Set 4th byte only if record size < 64
26160		RET
26170	
26180	
26190	SELDSK:	;System call 14
26200		MOV	DH,0
26210		MOV	BX,DX
26220		PUSH	CS
26230		POP	DS
26240		MOV	AL,[NUMDRV]
26250		CMP	BL,AL
26260		JNB	RET
26270		SHL	BX
26280		MOV	DX,[BX+CURDRVPT+2]
26290		MOV	[CURDRVPT],DX
26300		RET
26310	
26320	
26330	BUFIN:	;System call 10
26340		MOV	AX,CS
26350		MOV	ES,AX
26360		MOV	SI,DX
26370		MOV	CH,0
26380		LODW
26390		OR	AL,AL
26400		JZ	RET
26410		MOV	BL,AH
26420		MOV	BH,CH
26430		CMP	AL,BL
26440		JBE	NOEDIT
26450		CMP	B,[BX+SI],0DH
26460		JZ	EDITON
26470	NOEDIT:
26480		MOV	BL,CH
26490	EDITON:
26500		MOV	DL,AL
26510		DEC	DX
26520	NEWLIN:
26530		SEG	CS
26540		MOV	AL,[CARPOS]
26550		SEG	CS
26560		MOV	[STARTPOS],AL
26570		PUSH	SI
26580		MOV	DI,INBUF
26590		MOV	AH,CH
26600		MOV	BH,CH
26610		MOV	DH,CH
26620	GETCH:
26630		CALL	IN
26640		CMP	AL,7FH
26650		JZ	BACKSPJ
26660		CMP	AL,8
26670		JZ	BACKSPJ
26680		CMP	AL,13
26690		JZ	ENDLIN
26700		CMP	AL,10
26710		JZ	PHYCRLF
26720		CMP	AL,"X"-"@"
26730		JZ	KILNEW
26740		CMP	AL,1BH
26750		JZ	KILNEW		;WANT esc TO DO SAME AS cntrl-X
26760		CMP	AL,ESCCH
26770		JZ	ESC
26780	SAVCH:
26790		CMP	DH,DL
26800		JAE	BELL
26810		STOB
26820		INC	DH
26830		CALL	BUFOUT
26840		OR	AH,AH
26850		JNZ	GETCH
26860		CMP	BH,BL
26870		JAE	GETCH
26880		INC	SI
26890		INC	BH
26900		JP	GETCH
26910	
26920	BELL:
26930		MOV	AL,7
26940		CALL	OUTCH
26950		JP	GETCH
26960	
26970	BACKSPJ:JP	BACKSP
26980	
26990	ESC:
27000		CALL	IN
27010		PUSH	DI
27020		MOV	CL,ESCTABLEN
27030		MOV	DI,ESCTAB
27040		REPNE
27050		SCAB
27060		POP	DI
27070		MOV	BP,CX
27080		SHL	BP
27090		SEG	CS		;To work in init
27100		JMP	[BP+ESCFUNC]
27110	
27120	ENDLIN:
27130		STOB
27140		CALL	OUT
27150		POP	DI
27160		MOV	[DI-1],DH
27170		INC	DH
27180	COPYNEW:
27190		MOV	BP,ES
27200		MOV	BX,DS
27210		MOV	ES,BX
27220		MOV	DS,BP
27230		MOV	SI,INBUF
27240		MOV	CL,DH
27250		REP
27260		MOVB
27270		RET
27280	CRLF:
27290		MOV	AL,13
27300		CALL	OUT
27310		MOV	AL,10
27320		JMP	OUT
27330	
27340	PHYCRLF:
27350		CALL	CRLF
27360		JP	GETCH
27370	
27380	KILNEW:
27390		MOV	AL,"\"
27400		CALL	OUT
27410		POP	SI
27420	PUTNEW:
27430		CALL	CRLF
27440		SEG	CS
27450		MOV	AL,[STARTPOS]
27460		CALL	TAB
27470		JMP	NEWLIN
27480	
27490	BACKSP:
27500		OR	DH,DH
27510		JZ	OLDBAK
27520		CALL	BACKUP
27530		SEG	ES
27540		MOV	AL,[DI]
27550		CMP	AL," "
27560		JAE	OLDBAK
27570		CMP	AL,9
27580		JZ	BAKTAB
27590		CALL	BACKMES
27600	OLDBAK:
27610		OR	AH,AH
27620		JNZ	GETCH1
27630		OR	BH,BH
27640		JZ	GETCH1
27650		DEC	BH
27660		DEC	SI
27670	GETCH1:
27680		JMP	GETCH
27690	BAKTAB:
27700		PUSH	DI
27710		DEC	DI
27720		DOWN
27730		MOV	CL,DH
27740		MOV	AL," "
27750		PUSH	BX
27760		MOV	BL,7
27770		JCXZ	FIGTAB
27780	FNDPOS:
27790		SCAB
27800		JNA	CHKCNT
27810		SEG	ES
27820		CMP	B,[DI+1],9
27830		JZ	HAVTAB
27840		DEC	BL
27850	CHKCNT:
27860		LOOP	FNDPOS
27870	FIGTAB:
27880		SEG	CS
27890		SUB	BL,[STARTPOS]
27900	HAVTAB:
27910		SUB	BL,DH
27920		ADD	CL,BL
27930		AND	CL,7
27940		UP
27950		POP	BX
27960		POP	DI
27970		JZ	OLDBAK
27980	TABBAK:
27990		CALL	BACKMES
28000		LOOP	TABBAK
28010		JP	OLDBAK
28020	BACKUP:
28030		DEC	DH
28040		DEC	DI
28050	BACKMES:
28060		MOV	AL,8
28070		CALL	OUT
28080		MOV	AL," "
28090		CALL	OUT
28100		MOV	AL,8
28110		JMP	OUT
28120	
28130	TWOESC:
28140		MOV	AL,ESCCH
28150		JMP	SAVCH
28160	
28170	COPYLIN:
28180		MOV	CL,BL
28190		SUB	CL,BH
28200		JP	COPYEACH
28210	
28220	COPYSTR:
28230		CALL	FINDOLD
28240		JP	COPYEACH
28250	
28260	COPYONE:
28270		MOV	CL,1
28280	COPYEACH:
28290		MOV	AH,0		;Turn off insert mode when copying
28300		CMP	DH,DL
28310		JZ	GETCH2
28320		CMP	BH,BL
28330		JZ	GETCH2
28340		LODB
28350		STOB
28360		CALL	BUFOUT
28370		INC	BH
28380		INC	DH
28390		LOOP	COPYEACH
28400	GETCH2:
28410		JMP	GETCH
28420	
28430	SKIPONE:
28440		CMP	BH,BL
28450		JZ	GETCH2
28460		INC	BH
28470		INC	SI
28480		JMP	GETCH
28490	
28500	SKIPSTR:
28510		CALL	FINDOLD
28520		ADD	SI,CX
28530		ADD	BH,CL
28540		JMP	GETCH
28550	
28560	FINDOLD:
28570		CALL	IN
28580		MOV	CL,BL
28590		SUB	CL,BH
28600		JZ	NOTFND
28610		DEC	CX
28620		JZ	NOTFND
28630		PUSH	ES
28640		PUSH	DS
28650		POP	ES
28660		PUSH	DI
28670		MOV	DI,SI
28680		INC	DI
28690		REPNE
28700		SCAB
28710		POP	DI
28720		POP	ES
28730		JNZ	NOTFND
28740		NOT	CL
28750		ADD	CL,BL
28760		SUB	CL,BH
28770		RET
28780	NOTFND:
28790		POP	BP
28800		JMP	GETCH
28810	
28820	REEDIT:
28830		MOV	AL,"@"
28840		CALL	OUT
28850		POP	DI
28860		PUSH	DI
28870		PUSH	ES
28880		PUSH	DS
28890		CALL	COPYNEW
28900		POP	DS
28910		POP	ES
28920		POP	SI
28930		MOV	BL,DH
28940		JMP	PUTNEW
28950	
28960	TOGGLINS:
28970		NOT	AH
28980		JMP	GETCH
28990	
29000	CTRLZ:
29010		MOV	AL,1AH
29020		JMP	SAVCH
29030	
29040	ESCFUNC:
29050		DW	GETCH
29060		DW	TWOESC
29070		DW	TOGGLINS
29080		DW	BACKSP
29090		DW	REEDIT
29100		DW	CTRLZ
29110		DW	COPYLIN
29120		DW	SKIPSTR
29130		DW	COPYSTR
29140		DW	SKIPONE
29150		DW	COPYONE
29160		DW	COPYONE
29170	
29180	BUFOUT:
29190		CMP	AL," "
29200		JAE	OUT
29210		CMP	AL,9
29220		JZ	OUT
29230		PUSH	AX
29240		MOV	AL,"^"
29250		CALL	OUT
29260		POP	AX
29270		OR	AL,40H
29280		JP	OUT
29290	
29300	CONOUT:	;System call 2
29310		MOV	AL,DL
29320	OUT:
29330		CMP	AL,20H
29340		JB	CTRLOUT
29350		CMP	AL,7FH
29360		JZ	OUTCH
29370		SEG	CS
29380		INC	B,[CARPOS]
29390	OUTCH:
29400		PUSH	AX
29410		CALL	STATCHK
29420		POP	AX
29430		CALL	BIOSOUT,BIOSSEG
29440		SEG	CS
29450		TEST	B,[PFLAG],-1
29460		JZ	RET
29470		CALL	BIOSPRINT,BIOSSEG
29480		RET
29490	
29500	NOSTOP:
29510		CMP	AL,"P"-"@"
29520		JZ	INCHK
29530		CMP	AL,"C"-"@"
29540		JZ	INCHK
29550		RET
29560	
29570	STATCHK:
29580		CALL	BIOSSTAT,BIOSSEG
29590		JZ	RET
29600		CMP	AL,'S'-'@'
29610		JNZ	NOSTOP
29620		CALL	BIOSIN,BIOSSEG	;Eat Ctrl-S character
29630	INCHK:
29640		CALL	BIOSIN,BIOSSEG
29650		CMP	AL,'P'-'@'
29660		JZ	PRINTOGL
29670		CMP	AL,'C'-'@'
29680		JNZ	RET
29690	; Ctrl-C handler.
29700	; If function 9 or 10 was in progress, a backslash, CR, and LF are printed
29710	; to show line is canceled. Then the user registers are restored and the
29720	; user CTRL-C handler is executed. At this point the top of the stack has
29730	; 1) the interrupt return address should the user CTRL-C handler wish to
29740	; allow processing to continue; 2) the original interrupt return address
29750	; to the code that performed the function call in the first place. If the
29760	; user CTRL-C handler wishes to continue, it must leave all registers
29770	; unchanged and IRET. The function that was interrupted will simply be
29780	; repeated.
29790		SEG	CS
29800		MOV	AL,[FUNC]	;Get currently executing function
29810		CMP	AL,10		;Check if buffered line input
29820		JZ	CANLIN
29830		CMP	AL,9		;Check if buffered line output
29840		JNZ	RESTREG
29850	CANLIN:
29860		MOV	AL,"\"		;Display cancel line symbol
29870		CALL	OUT
29880		CALL	CRLF
29890	RESTREG:
29900		DI			;Prepare to play with stack
29910		SEG	CS
29920		MOV	SS,[SSSAVE]
29930		SEG	CS
29940		MOV	SP,[SPSAVE]	;User stack now restored
29950		POP	AX
29960		POP	BX
29970		POP	CX
29980		POP	DX
29990		POP	SI
30000		POP	DI
30010		POP	BP
30020		POP	DS
30030		POP	ES		;User registers now restored
30040		INT	CONTC		;Execute user Ctrl-C handler
30050		JMP	COMMAND		;Repeat command otherwise
30060	
30070	PRINTOGL:
30080		SEG	CS
30090		XOR	B,[PFLAG],1
30100		XOR	AL,AL		;Set zero flag--character not received
30110		RET
30120	CTRLOUT:
30130		CMP	AL,13
30140		JZ	ZERPOS
30150		CMP	AL,8
30160		JZ	BACKPOS
30170		CMP	AL,9
30180		JNZ	OUTCHJ
30190		SEG	CS
30200		MOV	AL,[CARPOS]
30210		OR	AL,0F8H
30220		NEG	AL
30230	TAB:
30240		PUSH	CX
30250		MOV	CL,AL
30260		MOV	CH,0
30265		JCXZ	POPTAB
30270	TABLP:
30280		MOV	AL," "
30290		CALL	OUT
30300		LOOP	TABLP
30305	POPTAB:
30310		POP	CX
30320		RET
30330	
30340	ZERPOS:
30350		SEG	CS
30360		MOV	B,[CARPOS],0
30370	OUTCHJ:	JMP	OUTCH
30380	
30390	BACKPOS:
30400		SEG	CS
30410		DEC	B,[CARPOS]
30420		JMP	OUTCH
30430	
30440	
30450	CONSTAT: ;System call 11
30460		CALL	BIOSSTAT,BIOSSEG
30470		MOV	AL,0
30480		JZ	RET
30490		OR	AL,-1
30500		RET
30510	
30520	
30530	CONIN:	;System call 1
30540		CALL	IN
30550		PUSH	AX
30560		CALL	OUT
30570		POP	AX
30580		RET
30590	
30600	
30610	IN:	;Internal input routine
30620		CALL	INCHK
30630		JZ	IN
30640		RET
30650	
30660	RAWIO:	;System call 6
30670		MOV	AL,DL
30680		CMP	AL,-1
30690		JNZ	RAWOUT
30700		CALL	BIOSSTAT,BIOSSEG
30710		MOV	AL,0
30720		JZ	RET
30730	RAWINP:	;System call 7
30740		CALL	BIOSIN,BIOSSEG
30750		RET
30760	RAWOUT:
30770		CALL	BIOSOUT,BIOSSEG
30780		RET
30790	
30800	LIST:	;System call 5
30810		MOV	AL,DL
30820	LISTOUT:
30830		PUSH	AX
30840		CALL	STATCHK
30850		POP	AX
30860		CALL	BIOSPRINT,BIOSSEG
30870		RET
30880	
30890	PRTBUF:	;System call 9
30900		MOV	SI,DX
30910	OUTSTR:
30920		LODB
30930		CMP	AL,"$"
30940		JZ	RET
30950		CALL	OUT
30960		JP	OUTSTR
30970	
30980	OUTMES:	;String output for internal messages
30990		SEG	CS
31000		LODB
31010		CMP	AL,"$"
31020		JZ	RET
31030		CALL	OUT
31040		JP	OUTMES
31050	
31060	
31070	MAKEFCB: ;Interrupt call 41
31080		MOV	DL,0		;Flag--not ambiguous file name
31090		OR	AL,AL		;Scan off separators if not zero
31100		JZ	NOSCAN
31110	SCAN:
31120		CALL	GETLET
31130		JZ	SCAN		;Get rid of leading separators (e.g., blanks)
31140		DEC	SI		;Point back to first non-separator
31150	NOSCAN:
31160		MOV	AL,0
31170		CMP	B,[SI],20H	;Check for termination character
31180		JB	HAVDRV
31190		CMP	B,[SI+1],":"	;Check for potential drive specifier
31200		JNZ	HAVDRV
31210		CALL	GETLET
31220		SUB	AL,"@"		;Convert drive letter to binary drive number
31230		JBE	BADDRV		;Valid drive numbers are 1-15
31240		SEG	CS
31250		CMP	AL,[NUMDRV]
31252		JBE	OKDRV
31254	BADDRV:
31256		MOV	DL,-1
31258	OKDRV:
31270		INC	SI		;Skip over colon
31280	HAVDRV:
31290		STOB			;Put drive specifier in first byte
31300		MOV	CX,8
31310		CALL	GETWORD		;Get 8-letter file name
31320		CMP	B,[SI],"."
31330		JNZ	NODOT
31340		INC	SI		;Skip over dot if present
31350	NODOT:
31360		MOV	CX,3		;Get 3-letter extension
31370		CALL	GETWORD
31380		SEG	CS
31390		LDS	BX,[SPSAVE]
31400		MOV	[BX+SISAVE],SI
31410		XOR	AX,AX
31420		STOW
31430		STOW
31440		MOV	AL,DL
31450		RET
31460	
31510	GETWORD:
31520		CALL	GETLET
31530		JZ	FILLNAM		;Exit if invalid character
31540		CMP	AL," "
31550		JBE	FILLNAM
31560		CMP	AL,"*"		;Check for ambiguous file specifier
31570		JNZ	NOSTAR
31580		MOV	AL,"?"
31590		DEC	CX
31600		REP
31610		STOB			;Fill rest of word with "?"
31620		INC	CX
31630	NOSTAR:
31640		STOB
31650		CMP	AL,"?"
31660		JNZ	NOTQ
31670		OR	DL,1		;Flag ambiguous file name
31680	NOTQ:
31690		LOOP	GETWORD
31700		INC	SI		;Point to "termination" character
31710	FILLNAM:
31720		MOV	AL," "
31730		REP
31740		STOB
31750		DEC	SI
31760		RET
31770	
31780	GETLET:
31790		LODB
31800		AND	AL,7FH
31810		CMP	AL,"a"
31820		JB	CHK
31830		CMP	AL,"z"
31840		JA	CHK
31850		SUB	AL,20H		;Convert to upper case
31860	CHK:
31870		CMP	AL," "
31880		JZ	RET
31890		CMP	AL,"="
31900		JZ	RET
31910		CMP	AL,","
31920		JZ	RET
31930		CMP	AL,";"
31940		JZ	RET
31950		CMP	AL,"."
31960		JZ	RET
31970		CMP	AL,":"
31980		JZ	RET
31990		CMP	AL,'"'
32000		JZ	RET
32010		CMP	AL,"+"
32020		JZ	RET
32030		CMP	AL,"/"
32040		JZ	RET
32050		CMP	AL,"["
32060		JZ	RET
32070		CMP	AL,"]"
32080		JZ	RET
32090		CMP	AL,9		;Filter out TABs too
32100		RET
32110	
32120	
32130	SETVECT: ; Interrupt call 37
32140		XOR	BX,BX
32150		MOV	ES,BX
32160		MOV	BL,AL
32170		SHL	BX
32180		SHL	BX
32190		SEG	ES
32200		MOV	[BX],DX
32210		SEG	ES
32220		MOV	[BX+2],DS
32230		RET
32240	
32250	
32260	NEWBASE: ; Interrupt call 38
32270		MOV	ES,DX
32280		SEG	CS
32290		LDS	SI,[SPSAVE]
32300		MOV	DS,[SI+CSSAVE]
32310		XOR	SI,SI
32320		MOV	DI,SI
32330		MOV	CX,80H
32340		REP
32350		MOVW
32360	
32370	SETMEM:
32380	
32390	; Inputs:
32400	;	DX = Segment
32410	; Function:
32420	;	Completely prepares a program base at the 
32430	;	specified segment.
32440	; Outputs:
32450	;	DS = DX
32460	;	ES = DX
32470	;	[0] has INT 20H
32480	;	[2] = First unavailable segment ([ENDMEM])
32490	;	[5] to [9] form a long call to the entry point
32500	;	[10] to [13] have exit address (from INT 22H)
32510	;	[14] to [17] have ctrl-C exit address (from INT 23H)
32520	; AX,DX,BP unchanged. All other registers destroyed.
32530	
32540		XOR	CX,CX
32550		MOV	DS,CX
32560		MOV	ES,DX
32570		MOV	SI,EXIT
32580		MOV	DI,SAVEXIT
32590		MOVW
32600		MOVW
32610		MOVW
32620		MOVW
32630		SEG	CS
32640		MOV	CX,[ENDMEM]
32650		SEG	ES
32660		MOV	[2],CX
32670		SUB	CX,DX
32680		CMP	CX,MAXDIF
32690		JBE	HAVDIF
32700		MOV	CX,MAXDIF
32710	HAVDIF:
32720		MOV	BX,ENTRYPOINTSEG
32730		SUB	BX,CX
32740		SHL	CX
32750		SHL	CX
32760		SHL	CX
32770		SHL	CX
32780		MOV	DS,DX
32790		MOV	[6],CX
32800		MOV	[8],BX
32810		MOV	[0],20CDH	;"INT INTTAB"
32820		MOV	B,[5],LONGCALL
32830		RET
32840	
32850	
32860	SHFTDI7:
32870		SHL	DI
32880		SHL	DI
32890		SHL	DI
32900		SHL	DI
32910		SHL	DI
32920		SHL	DI
32930		SHL	DI
32940		RET
32950	
32960	DATE16:
32970		PUSH	CX
32980		PUSH	DX
32990		PUSH	BX
33000		CALL	READTIME
33010		POP	BX
33020		POP	DX
33030		POP	CX
33040		MOV	AX,[MONTH]	;Fetch month and year
33050		SHL	AL		;Push month to left to make room for day
33060		SHL	AL
33070		SHL	AL
33080		SHL	AL
33090		SHL	AX
33100		OR	AL,[DAY]
33110		RET
33120	
33130	READTIME:
33140	;Gets tick count in CX:DX. Causes date rollover if new day has started
33150	;since last call. Destroys AX, BX.
33160		MOV	AH,0		;Request get time
33170		INT	1AH		;Time-of-day interrupt
33180		OR	AL,AL		;See if day has changed
33190		JZ	RET
33200		ADD	AL,[DAY]
33210		MOV	[DAY],AL
33220		MOV	AH,AL
33230		MOV	AL,[MONTH]
33240		MOV	BX,DAYTAB-1	;Table of days in each month
33250		XLAT			;Get number of days in current month
33260		SUB	AH,AL		;Have we rolled into next month?
33270		JBE	RET
33280		MOV	[DAY],AH	;Yes-store day of new month
33290		MOV	AL,[MONTH]
33300		INC	AL
33310		MOV	[MONTH],AL
33320		CMP	AL,12		;Have we rolled into next year?
33330		JBE	RET
33340		MOV	B,[MONTH],1	;Set first month to January
33350		MOV	AL,[YEAR]
33360		INC	AL
33370	SETYEAR:
33380	;Set year with value in AL. Adjust length of February for this year.
33390		MOV	[YEAR],AL
33400		AND	AL,3		;Check for leap year
33410		MOV	AL,28
33420		JNZ	SAVFEB		;28 days if no leap year
33430		INC	AL		;Add leap day
33440	SAVFEB:
33450		MOV	[DAYTAB+1],AL	;Store for February
33460		RET
33470	
33480	DAYTAB:	;Days of each month
33490		DB	31		;January
33500		DB	28		;February--reset each time year changes
33510		DB	31		;March
33520		DB	30		;April
33530		DB	31		;May
33540		DB	30		;June
33550		DB	31		;July
33560		DB	31		;August
33570		DB	30		;September
33580		DB	31		;October
33590		DB	30		;November
33600		DB	31		;December
33610	
33620	GETDATE: ;Function call 42
33630		PUSH	CS
33640		POP	DS
33650		CALL	READTIME	;Check for rollover to next day
33660		MOV	AX,[YEAR]
33670		MOV	BX,[DAY]
33680		LDS	SI,[SPSAVE]	;Get pointer to user registers
33690		MOV	[SI+DXSAVE],BX	;DH=month, DL=day
33700		ADD	AX,1980		;Put bias back
33710		MOV	[SI+CXSAVE],AX	;CX=year
33720		XOR	AL,AL
33730		RET
33740	
33750	SETDATE: ;Function call 43
33760		MOV	AL,-1		;Be ready to flag an error
33770		SUB	CX,1980		;Fix bias in year
33780		JC	RET		;Error if not big enough
33790		CMP	CX,119		;Year must be less than 2100
33800		JA	RET
33810		OR	DH,DH
33820		JZ	RET
33830		OR	DL,DL
33840		JZ	RET		;Error if either month or day is 0
33850		CMP	DH,12		;Check against max. month
33860		JA	RET
33870		PUSH	CS
33880		POP	DS
33890		CMP	DH,2		;Check for Feb.--needs special handling
33900		JNE	DAYCHK
33910		CMP	DL,29
33920		JA	RET		;Max 29 days in Feb.
33930		JB	DAYOK		;If 28 or less, definitely OK
33940		TEST	CL,3		;Check for leap year
33950		JZ	DAYOK		;If it is, 29 days OK
33960		RET			;Error if it's not
33970	DAYCHK:
33980		MOV	AL,DH
33990		MOV	BX,DAYTAB-1
34000		XLAT			;Look up days in month
34010		CMP	AL,DL
34020		MOV	AL,-1		;Restore error flag, just in case
34030		JB	RET		;Error if too many days
34040	DAYOK:
34050		PUSH	DX
34060		PUSH	CX
34070		MOV	AH,0
34080		INT	1AH		;Read time to clear day overflow
34090		POP	AX		;Year
34100		CALL	SETYEAR
34110		POP	[DAY]		;Set both day and month
34120		XOR	AL,AL		;Flag OK
34130		RET
34140	
34150	;***************************************
34160	; Time Functions
34170	;
34180	; Uses clock with 1,193,180/65536 ticks per second. User sees only
34190	; time in hours, minutes, seconds, and 1/100 second, in registers
34200	; CH, CL, DH, DL respectively. (Each is a binary number.) To
34210	; convert, ticks are multiplied by  (5 * 2**16)/59659, which is the
34220	; reciprocal of the tick rate. To convert the other way, 1/100 secs
34230	; is multiplied by  59659/(5 * 2**16).
34240	
34250	GETTIME: ;Function call 44
34260		PUSH	CS
34270		POP	DS
34280		CALL	READTIME	;Get tick count in CX:DX
34290	;First multiply by 5
34300		MOV	AX,CX
34310		MOV	BX,DX
34320		SHL	DX
34330		RCL	CX		;Times 2
34340		SHL	DX
34350		RCL	CX		;Times 4
34360		ADD	DX,BX
34370		ADC	AX,CX		;Times 5
34380		XCHG	AX,DX
34390		MOV	CX,59659
34400		DIV	AX,CX
34410		MOV	BX,AX		;Save quotient
34420		XOR	AX,AX		;Extend precision
34430		DIV	AX,CX
34440	;Rounding based on the remainder may be added here
34450	;The result in BX:AX is time in 1/100 second.
34460		MOV	DX,BX
34470		MOV	CX,200		;Extract 1/100's
34480	;Division by 200 is necessary to ensure no overflow--max result
34490	;is number of seconds in a day/2 = 43200.
34500		DIV	AX,CX
34510		CMP	DL,100		;Remainder over 100?
34520		JB	NOADJ
34530		SUB	DL,100		;Keep 1/100's less than 100
34540	NOADJ:
34550		CMC			;If we subtracted 100, carry is now set
34560		MOV	BL,DL		;Save 1/100's
34570	;To compensate for dividing by 200 instead of 100, we now multiply
34580	;by two, shifting a one in if the remainder had exceeded 100.
34590		RCL	AX
34600		MOV	DL,0
34610		RCL	DX
34620		MOV	CX,60		;Divide out seconds
34630		DIV	AX,CX
34640		MOV	BH,DL		;Save the seconds
34650		DIV	AL,CL		;Break into hours and minutes
34660		XCHG	AL,AH
34670	;Time is now in AX:BX (hours, minutes, seconds, 1/100 sec)
34680		LDS	SI,[SPSAVE]	;Get pointer to user registers
34690		MOV	[SI+DXSAVE],BX
34700		MOV	[SI+CXSAVE],AX
34710		XOR	AL,AL
34720		RET
34730	
34740	SETTIME: ;Function call 45
34750	;Time is in CX:DX in hours, minutes, seconds, 1/100 sec
34760		MOV	AL,-1		;Flag in case of error
34770		CMP	CH,24		;Check hours
34780		JAE	RET
34790		CMP	CL,60		;Check minutes
34800		JAE	RET
34810		CMP	DH,60		;Check seconds
34820		JAE	RET
34830		CMP	DL,100		;Check 1/100's
34840		JAE	RET
34850		MOV	AL,60
34860		MUL	AL,CH		;Hours to minutes
34870		MOV	CH,0
34880		ADD	AX,CX		;Total minutes
34890		MOV	CX,6000		;60*100
34900		MOV	BX,DX		;Get out of the way of the multiply
34910		MUL	AX,CX		;Convert to 1/100 sec
34920		MOV	CX,AX
34930		MOV	AL,100
34940		MUL	AL,BH		;Convert seconds to 1/100 sec
34950		ADD	CX,AX		;Combine seconds with hours and min.
34960		ADC	DX,0		;Ripple carry
34970		MOV	BH,0
34980		ADD	CX,BX		;Combine 1/100 sec
34990		ADC	DX,0
35000	;DX:CX is time in 1/100 sec
35010		XCHG	AX,DX
35020		XCHG	AX,CX		;Now time is in CX:AX
35030		MOV	BX,59659
35040		MUL	AX,BX		;Multiply low half
35050		XCHG	DX,CX
35060		XCHG	AX,DX		;CX->AX, AX->DX, DX->CX
35070		MUL	AX,BX		;Multiply high half
35080		ADD	AX,CX		;Combine overlapping products
35090		ADC	DX,0
35100		XCHG	AX,DX		;AX:DX=time*59659
35110		MOV	BX,5
35120		DIV	AL,BL		;Divide high half by 5
35130		MOV	CL,AL
35140		MOV	CH,0
35150		MOV	AL,AH		;Remainder of divide-by-5
35160		CBW
35170		XCHG	AX,DX		;Use it to extend low half
35180		DIV	AX,BX		;Divde low half by 5
35190		MOV	DX,AX
35200	;CX:DX now has time in ticks
35210		MOV	AH,1
35220		INT	1AH		;Set clock
35230		XOR	AL,AL		;Return no error
35240		RET
35250	
35260	;***** DATA AREA *****
35270	
35280	;Device number mapping
35290	;0,1 = CON, AUX (Bidirectional devices)
35300	;2,3 = Printer, bit bucket (output only)
35310	
35320	IONAME:	DB	"PRN ","LPT1","AUX ","COM1","CON ","NUL "
35330	IONUM:	DB	3,0,1,1,2,2
35340	
35350	CARPOS:	DB	0
35360	INSFLG:	DB	0
35370	STARTPOS:DB	0
35380	PFLAG:	DB	0
35390	DAY:	DB	0
35400	MONTH:	DB	0
35410	YEAR:	DW	0
35420	DIRTYDIR:DB	0	;Dirty buffer flag
35430	NUMDRV:	DS	1	;Number of drives
35440	CONTPOS:DW	0
35450	DMAADD:	DW	80H	;User's disk transfer address (disp/seg)
35460		DS	2
35470	ENDMEM:	DS	2
35480	MAXSEC:	DW	0
35490	BUFFER:	DS	2
35500	BUFSECNO:DW	0
35510	BUFDRVNO:DB	-1
35520	DIRTYBUF:DB	0
35530	BUFDRVBP:DS	2
35540	DIRBUFID:DW	-1
35550	CURDRVPT:DS	2
35560	DRVTAB:	DS	30	;Enough for 15 drives
35570	INBUF:	DS	15	;Only the first part
35580	
35590	; Init code overlaps with data area below
35600	
35610	INITCODE:
35620	
35630		DS	128-15	;More of INBUF
35640	CONBUF:	DS	130	;The rest of INBUF and console buffer
35650	FUNC:	DS	1	;Currently executing function code
35660	LASTENT:DS	2
35670	EXITHOLD:DS	4
35680	FATBASE:DS	2
35690	NAME1:	DS	11	;File name buffer
35700	ATTRIB:	DS	1	;Search attributes
35710	NAME2:	DS	11
35715	NAME3:	DS	12
35720	EXTFCB:	DS	1
35730	CREATING:DS	1
35740	TEMP:
35750	SPSAVE:	DS	2
35760	SSSAVE:	DS	2
35770	CONTSTK:DS	2
35780	SECCLUSPOS:DS	1	;Position of first sector within cluster
35790	DSKERR:	DS	1
35800	TRANS:	DS	1
35810	PREREAD:DS	1		;0 means must preread; 1 means optional
35820	READOP:	DS	1
35830	
35840		ALIGN
35850	FCB:	DS	2	;Address of user FCB
35860	NEXTADD:DS	2
35870	RECPOS:	DS	4
35880	RECCNT:	DS	2
35890	LASTPOS:DS	2
35900	CLUSNUM:DS	2
35910	SECPOS:	DS	2		;Position of first sector accessed
35920	VALSEC:	DS	2		;Number of valid (previously written) sectors
35930	BYTSECPOS:DS	2	;Position of first byte within sector
35940	BYTPOS:	DS	4		;Byte position in file of access
35950	BYTCNT1:DS	2		;No. of bytes in first sector
35960	BYTCNT2:DS	2		;No. of bytes in last sector
35970	SECCNT:	DS	2		;No. of whole sectors
35980	
35990		DS	100H	;Stack space
36000	IOSTACK:
36010		DS	100H
36020	DSKSTACK:
36030	
36040		IF	DSKTEST
36050	NSS:	DS	2
36060	NSP:	DS	2
36070		ENDIF
36080	
36090	DIRBUF:
36100	
36110	;Init code below overlaps with data area above
36120	
36130		ORG	INITCODE
36140		PUT	$+100H
36150	
36160	MOVFAT:
36170	;This section of code is safe from being overwritten by block move
36180		SEG	ES
36190		REP
36200		MOVB
36210		UP
36220	FININIT:
36230		CALL	SETMEM		;Set up segment
36240		RET	L
36250	
36260	DOSINIT:
36270		DI
36280		UP
36290		PUSH	CS
36300		POP	ES
36310		LODB
36320		SEG	ES
36330		MOV	[NUMDRV],AL
36340		MOV	BX,DRVTAB
36350		MOV	DI,MEMSTRT
36360	PERDRV:
36370		SEG	ES
36380		MOV	[BX],DI
36390		MOV	BP,DI
36400		INC	BX
36410		INC	BX
36420		SEG	ES
36430		MOV	AL,[DRVCNT]
36440		STOB			;DRVNUM
36450		LODW			;Pointer to DPT
36460		PUSH	SI
36470		MOV	SI,AX
36480		LODW
36490		STOW			;SECSIZ
36500		MOV	DX,AX
36510		SEG	ES
36520		CMP	AX,[MAXSEC]
36530		JBE	NOTMAX
36540		SEG	ES
36550		MOV	[MAXSEC],AX
36560	NOTMAX:
36570		LODB
36580		DEC	AL
36590		STOB			;CLUSMSK
36600		JZ	HAVSHFT
36610		CBW
36620	FIGSHFT:
36630		INC	AH
36640		SAR	AL
36650		JNZ	FIGSHFT
36660		MOV	AL,AH
36670	HAVSHFT:
36680		STOB			;CLUSSHFT
36690		MOVW			;FIRFAT (= number of reserved sectors)
36700		MOVB			;FATCNT
36710		MOVW			;MAXENT
36720		MOV	AX,DX		;SECSIZ again
36730		MOV	CL,5
36740		SHR	AX,CL
36750		MOV	CX,AX		;Directory entries per sector
36760		DEC	AX
36770		SEG	ES
36780		ADD	AX,[BP+MAXENT]
36790		XOR	DX,DX
36800		DIV	AX,CX
36810		STOW			;DIRSEC (temporarily)
36820		SHR	AX		;Divide by two
36830		ADC	AX,0		;Round up
36840		SEG	ES
36850		MOV	[SDIRSEC],AX	;Number of directory records for small entries
36860		MOVW			;DSKSIZ (temporarily)
36870	FNDFATSIZ:
36880		MOV	AL,1
36890		MOV	DX,1
36900	GETFATSIZ:
36910		PUSH	DX
36920		CALL	FIGFATSIZ
36930		POP	DX
36940		CMP	AL,DL		;Compare newly computed FAT size with trial
36950		JZ	HAVFATSIZ	;Has sequence converged?
36960		CMP	AL,DH		;Compare with previous trial
36970		MOV	DH,DL
36980		MOV	DL,AL		;Shuffle trials
36990		JNZ	GETFATSIZ	;Continue iterations if not oscillating
37000		SEG	ES
37010		DEC	[BP+DSKSIZ]	;Damp those oscillations
37020		JP	FNDFATSIZ	;Try again
37030	HAVFATSIZ:
37040		STOB			;FATSIZ
37050		SEG	ES
37060		MUL	AL,[BP+FATCNT]	;Space occupied by all FATs
37070		SEG	ES
37080		ADD	AX,[BP+FIRFAT]
37090		STOW			;FIRDIR
37100	
37110		IF	SMALLDIR-1
37120		SEG	ES
37130		ADD	AX,[BP+DIRSEC]
37140		SEG	ES
37150		MOV	[BP+FIRREC],AX	;Destroys DIRSEC
37160		CALL	FIGMAX
37170		SEG	ES
37180		MOV	[BP+MAXCLUS],CX
37190		ENDIF
37200	
37210		IF	SMALLDIR
37220		MOV	DX,AX		;Save FIRDIR momentarily
37230		SEG	ES
37240		ADD	AX,[SDIRSEC]	;Add number of dir. sectors for 16-byte entry
37250		STOW			;FIRREC1
37260		XCHG	AX,CX		;Previously computed MAXCLUS
37270		STOW			;MAXCLUS1
37280		XCHG	DX,AX
37290		SEG	ES
37300		ADD	AX,[BP+DIRSEC]	;Add number of dir. sectors for 32-byte entry
37310		STOW			;FIRREC2
37320		CALL	FIGMAX
37330		XCHG	AX,CX
37340		STOW			;MAXCLUS2
37350		ENDIF
37360	
37370		MOV	AX,0FFH
37380		STOB			;DIRTYFAT
37390		SEG	ES
37400		MOV	AL,[BP+FATSIZ]
37410		SEG	ES
37420		MUL	AX,[BP+SECSIZ]
37430		ADD	DI,AX		;Allocate FAT
37440		POP	SI		;Restore pointer to init. table
37450		SEG	ES
37460		MOV	AL,[DRVCNT]
37470		INC	AL
37480		SEG	ES
37490		MOV	[DRVCNT],AL
37500		SEG	ES
37510		CMP	AL,[NUMDRV]
37520		JAE	CONTINIT
37530		JMP	PERDRV	
37540	CONTINIT:
37550		LODW			;Max. buffer size
37560		SEG	ES
37570		MOV	BX,[MAXSEC]
37580		MOV	AX,DIRBUF
37590		ADD	AX,BX
37600		SEG	ES
37610		MOV	[BUFFER],AX	;Start of buffer
37620		PUSH	DI		;Save ending location
37630		ADD	DI,BX		;Allocate directory buffer
37640		ADD	DI,BX		;Allocate buffer space
37650		ADD	DI,ADJFAC+15	;True start of free space
37660		MOV	CL,4
37670		SHR	DI,CL		;First free segment
37680		MOV	BP,DI
37690		XOR	AX,AX
37700		MOV	DS,AX
37710		MOV	ES,AX
37720		MOV	DI,INTBASE
37730		MOV	AX,QUIT
37740		STOW			;Set abort address--displacement
37750		MOV	AX,CS
37760		MOV	B,[ENTRYPOINT],LONGJUMP
37770		MOV	[ENTRYPOINT+1],ENTRY
37780		MOV	[ENTRYPOINT+3],AX
37790		MOV	CX,9
37800		REP
37810		STOW				;Set 5 segments (skip 2 between each)
37820		MOV	[INTBASE+4],COMMAND
37830		MOV	[INTBASE+12],IRET	;CTRL-C exit
37840		MOV	[INTBASE+16],IRET	;Fatal error exit
37850		MOV	AX,BIOSREAD
37860		STOW
37870		MOV	AX,BIOSSEG
37880		STOW
37890		STOW	;Add 2 to DI
37900		STOW
37910		MOV	[INTBASE+18H],BIOSWRITE
37920		MOV	DX,CS
37930		MOV	DS,DX
37940		ADD	DX,BP
37950		MOV	[DMAADD],80H
37960		MOV	[DMAADD+2],DX
37970		MOV	AX,[DRVTAB]
37980		MOV	[CURDRVPT],AX
37990		INT	12H		;Get memory size--1K blocks in AX
38000		MOV	CL,6
38010		SHL	AX,CL		;Convert to 16-byte blocks (segment no.)
38020		SEG	CS
38030		MOV	[ENDMEM],AX
38040		XOR	CX,CX
38050		MOV	DS,CX
38060		MOV	[EXIT],100H
38070		MOV	[EXIT+2],DX
38080		PUSH	CS
38090		POP	DS
38100		PUSH	CS
38110		POP	ES
38120		MOV	[ENDDOS],DX
38130	;Move FATs into position. Segment of COMMAND still in DX.
38140		POP	SI
38150		MOV	AX,[MAXSEC]
38160		SHL	AX		;Allocate two buffers
38170		ADD	AX,ADJFAC
38180		JZ	FINJMP
38190		MOV	DI,DRVTAB
38200		MOV	CX,15
38210	ADJLP:
38220		ADD	[DI],AX
38230		INC	DI
38240		INC	DI
38250		LOOP	ADJLP
38260		MOV	CX,SI
38270		MOV	SI,MEMSTRT	;Place to move FATs from
38280		SUB	CX,SI		;Total length of FATs
38290		MOV	DI,AX
38300		ADD	DI,SI		;Place to move FATs to
38310		OR	AX,AX
38320		JS	MOVJMP
38330		DEC	CX
38340		ADD	DI,CX
38350		ADD	SI,CX
38360		INC	CX
38370		DOWN
38380	MOVJMP:
38390		JMP	MOVFAT
38400	FINJMP:	JMP	FININIT
38410	
38420	FIGFATSIZ:
38430		SEG	ES
38440		MUL	AL,[BP+FATCNT]
38450		SEG	ES
38460		ADD	AX,[BP+FIRFAT]
38470		SEG	ES
38480		ADD	AX,[SDIRSEC]	;Use small dir. entry to figure FAT size
38490	FIGMAX:
38500	;AX has equivalent of FIRREC
38510		SEG	ES
38520		SUB	AX,[BP+DSKSIZ]
38530		NEG	AX
38540		SEG	ES
38550		MOV	CL,[BP+CLUSSHFT]
38560		SHR	AX,CL
38570		INC	AX
38580		MOV	CX,AX		;MAXCLUS
38590		INC	AX
38600		MOV	DX,AX
38610		SHR	DX
38620		ADC	AX,DX		;Size of FAT in bytes
38630		SEG	ES
38640		MOV	SI,[BP+SECSIZ]
38650		ADD	AX,SI
38660		DEC	AX
38670		XOR	DX,DX
38680		DIV	AX,SI
38690		RET
38700	
38710	DRVCNT:	DB	0
38720	SDIRSEC:DS	1
38730	
38740	MEMSTRT:
38750	ADJFAC:	EQU	DIRBUF-MEMSTRT
38760	
38770		DS	EXCESS
38780		DB	0
 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**



 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**



                        * * * L P T S P L  R u n  L o g * * *

13:49:36 LPDAT  [LPTLSJ  LPTSPL version 102(2263) running on LPT000, 08-Jul-81 13:49:36]
13:49:36 LPDAT  [LPTSJS  Starting Job 86DOS, Seq #2408, request created at 08-Jul-81 13:49:36]
13:49:41 LPMSG  [LPTSTF  Starting File DSKC:86DOS.A86<055>[500,500]]
13:52:40 LPMSG  [LPTCPT  Checkpoint Taken during file DSKC:86DOS.A86<055>[500,500], copy 1, page 27]
13:55:40 LPMSG  [LPTCPT  Checkpoint Taken during file DSKC:86DOS.A86<055>[500,500], copy 1, page 56]
13:56:35 LPMSG  [LPTFPF  Finished Printing File DSKC:86DOS.A86<055>[500,500]]
13:56:35 LPSUM  Spooler runtime 1 Seconds, 9 KCS, 171 disk reads, 66 pages printed



 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**



 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**



 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**



 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**



 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**



 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**



 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**



 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**



 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**



 **END** User BASLIB-86 [20,67]  Job  86DOS Seq. 2408 Date 08-Jul-81 13:56:35 Monitor Microsoft 1091 603a4d80j **END**




000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111
000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999000000000011111111112222222222333
123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012
