Files
Yufeng Gao 8065d4d8be Initial commit
Initial import of the transcribed source code from Tim Paterson's
DOS listings.

Co-authored-by: RichCini <rich.cini@gmail.com>
2026-04-22 01:04:31 +10:00

4019 lines
95 KiB
Plaintext

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