Advertisement
Guest User

MS-DOS 1.25 source code

a guest
Mar 25th, 2014
2,975
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ; 86-DOS  High-performance operating system for the 8086  version 1.25
  2. ;       by Tim Paterson
  3.  
  4.  
  5. ; ****************** Revision History *************************
  6. ;          >> EVERY change must noted below!! <<
  7. ;
  8. ; 0.34 12/29/80 General release, updating all past customers
  9. ; 0.42 02/25/81 32-byte directory entries added
  10. ; 0.56 03/23/81 Variable record and sector sizes
  11. ; 0.60 03/27/81 Ctrl-C exit changes, including register save on user stack
  12. ; 0.74 04/15/81 Recognize I/O devices with file names
  13. ; 0.75 04/17/81 Improve and correct buffer handling
  14. ; 0.76 04/23/81 Correct directory size when not 2^N entries
  15. ; 0.80 04/27/81 Add console input without echo, Functions 7 & 8
  16. ; 1.00 04/28/81 Renumber for general release
  17. ; 1.01 05/12/81 Fix bug in `STORE'
  18. ; 1.10 07/21/81 Fatal error trapping, NUL device, hidden files, date & time,
  19. ;               RENAME fix, general cleanup
  20. ; 1.11 09/03/81 Don't set CURRENT BLOCK to 0 on open; fix SET FILE SIZE
  21. ; 1.12 10/09/81 Zero high half of CURRENT BLOCK after all (CP/M programs don't)
  22. ; 1.13 10/29/81 Fix classic "no write-through" error in buffer handling
  23. ; 1.20 12/31/81 Add time to FCB; separate FAT from DPT; Kill SMALLDIR;
  24. ;               Add FLUSH and MAPDEV calls; allow disk mapping in DSKCHG;
  25. ;               Lots of smaller improvements
  26. ; 1.21 01/06/82 HIGHMEM switch to run DOS in high memory
  27. ; 1.22 01/12/82 Add VERIFY system call to enable/disable verify after write
  28. ; 1.23 02/11/82 Add defaulting to parser; use variable escape character
  29. ;               Don't zero extent field in IBM version (back to 1.01!)
  30. ; 1.24 03/01/82 Restore fcn. 27 to 1.0 level; add fcn. 28
  31. ; 1.25 03/03/82 Put marker (00) at end of directory to speed searches
  32. ;
  33. ; *************************************************************
  34.  
  35.  
  36. ; Interrupt Entry Points:
  37.  
  38. ; INTBASE:      ABORT
  39. ; INTBASE+4:    COMMAND
  40. ; INTBASE+8:    BASE EXIT ADDRESS
  41. ; INTBASE+C:    CONTROL-C ABORT
  42. ; INTBASE+10H:  FATAL ERROR ABORT
  43. ; INTBASE+14H:  BIOS DISK READ
  44. ; INTBASE+18H:  BIOS DISK WRITE
  45. ; INTBASE+40H:  Long jump to CALL entry point
  46.  
  47.         IF      IBM
  48. ESCCH   EQU     0
  49. CANCEL  EQU     1BH             ;Cancel with ESC
  50. TOGLINS EQU     TRUE            ;One key toggles insert mode
  51. TOGLPRN EQU     TRUE            ;One key toggles printer echo
  52. NUMDEV  EQU     6               ;Include "COM1" as I/O device name
  53. ZEROEXT EQU     TRUE
  54.         ELSE
  55. ESCCH   EQU     1BH
  56. CANCEL  EQU     "X"-"@"         ;Cancel with Ctrl-X
  57. TOGLINS EQU     FALSE           ;Separate keys for insert mode on and off
  58. TOGLPRN EQU     FALSE           ;Separate keys for printer echo on and off
  59. NUMDEV  EQU     5               ;Number of I/O device names
  60. ZEROEXT EQU     FALSE
  61.         ENDIF
  62.  
  63. MAXCALL EQU     36
  64. MAXCOM  EQU     46
  65. INTBASE EQU     80H
  66. INTTAB  EQU     20H
  67. ENTRYPOINTSEG   EQU     0CH
  68. ENTRYPOINT      EQU     INTBASE+40H
  69. CONTC   EQU     INTTAB+3
  70. EXIT    EQU     INTBASE+8
  71. LONGJUMP EQU    0EAH
  72. LONGCALL EQU    9AH
  73. MAXDIF  EQU     0FFFH
  74. SAVEXIT EQU     10
  75.  
  76. ; Field definition for FCBs
  77.  
  78. FCBLOCK STRUC
  79.         DB      12 DUP (?)              ;Drive code and name
  80. EXTENT  DW      ?
  81. RECSIZ  DW      ?       ;Size of record (user settable)
  82. FILSIZ  DW      ?       ;Size of file in bytes
  83. DRVBP   DW      ?       ;BP for SEARCH FIRST and SEARCH NEXT
  84. FDATE   DW      ?       ;Date of last writing
  85. FTIME   DW      ?       ;Time of last writing
  86. DEVID   DB      ?       ;Device ID number, bits 0-5
  87.                         ;bit 7=0 for file, bit 7=1 for I/O device
  88.                         ;If file, bit 6=0 if dirty
  89.                         ;If I/O device, bit 6=0 if EOF (input)
  90. FIRCLUS DW      ?       ;First cluster of file
  91. LSTCLUS DW      ?       ;Last cluster accessed
  92. CLUSPOS DW      ?       ;Position of last cluster accessed
  93.         DB      ?       ;Forces NR to offset 32
  94. NR      DB      ?       ;Next record
  95. RR      DB      3 DUP (?)               ;Random record
  96. FCBLOCK ENDS
  97. FILDIRENT       = FILSIZ                ;Used only by SEARCH FIRST and SEARCH NEXT
  98.  
  99. ; Description of 32-byte directory entry (same as returned by SEARCH FIRST
  100. ; and SEARCH NEXT, functions 17 and 18).
  101. ;
  102. ; Location      bytes   Description
  103. ;
  104. ;    0          11      File name and extension ( 0E5H if empty)
  105. ;   11           1      Attributes. Bits 1 or 2 make file hidden
  106. ;   12          10      Zero field (for expansion)
  107. ;   22           2      Time. Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
  108. ;   24           2      Date. Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
  109. ;   26           2      First allocation unit ( < 4080 )
  110. ;   28           4      File size, in bytes (LSB first, 30 bits max.)
  111. ;
  112. ; The File Allocation Table uses a 12-bit entry for each allocation unit on
  113. ; the disk. These entries are packed, two for every three bytes. The contents
  114. ; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result
  115. ; to the base address of the Allocation Table; 3) fetching the 16-bit word at
  116. ; this address; 4) If N was odd (so that N*1.5 was not an integer), shift the
  117. ; word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number
  118. ; zero is used as an end-of-file trap in the OS and as a flag for directory
  119. ; entry size (if SMALLDIR selected). Entry 1 is reserved for future use. The
  120. ; first available allocation unit is assigned entry number two, and even
  121. ; though it is the first, is called cluster 2. Entries greater than 0FF8H are
  122. ; end of file marks; entries of zero are unallocated. Otherwise, the contents
  123. ; of a FAT entry is the number of the next cluster in the file.
  124.  
  125.  
  126. ; Field definition for Drive Parameter Block
  127.  
  128. DPBLOCK STRUC
  129. DEVNUM  DB      ?       ;I/O driver number
  130. DRVNUM  DB      ?       ;Physical Unit number
  131. SECSIZ  DW      ?       ;Size of physical sector in bytes
  132. CLUSMSK DB      ?       ;Sectors/cluster - 1
  133. CLUSSHFT DB     ?       ;Log2 of sectors/cluster
  134. FIRFAT  DW      ?       ;Starting record of FATs
  135. FATCNT  DB      ?       ;Number of FATs for this drive
  136. MAXENT  DW      ?       ;Number of directory entries
  137. FIRREC  DW      ?       ;First sector of first cluster
  138. MAXCLUS DW      ?       ;Number of clusters on drive + 1
  139. FATSIZ  DB      ?       ;Number of records occupied by FAT
  140. FIRDIR  DW      ?       ;Starting record of directory
  141. FAT     DW      ?       ;Pointer to start of FAT
  142. DPBLOCK ENDS
  143.  
  144. DPBSIZ  EQU     20      ;Size of the structure in bytes
  145. DIRSEC  =       FIRREC  ;Number of dir. sectors (init temporary)
  146. DSKSIZ  =       MAXCLUS ;Size of disk (temp used during init only)
  147.  
  148. ;The following are all of the segments used
  149. ;They are declared in the order that they should be placed in the executable
  150.  
  151. CODE    SEGMENT
  152. CODE    ENDS
  153.  
  154. CONSTANTS       SEGMENT BYTE
  155. CONSTANTS       ENDS
  156.  
  157. DATA    SEGMENT WORD
  158. DATA    ENDS
  159.  
  160. DOSGROUP        GROUP   CODE,CONSTANTS,DATA
  161.  
  162. SEGBIOS SEGMENT
  163. SEGBIOS ENDS
  164.  
  165.  
  166. ; BOIS entry point definitions
  167.  
  168.         IF      IBM
  169. BIOSSEG EQU     60H
  170.         ENDIF
  171.         IF      NOT IBM
  172. BIOSSEG EQU     40H
  173.         ENDIF
  174.  
  175. SEGBIOS         SEGMENT AT BIOSSEG
  176.                 ORG     0
  177.                 DB      3 DUP (?)       ;Reserve room for jump to init code
  178. BIOSSTAT        DB      3 DUP (?)       ;Console input status check
  179. BIOSIN          DB      3 DUP (?)       ;Get console character
  180. BIOSOUT         DB      3 DUP (?)       ;Output console character
  181. BIOSPRINT       DB      3 DUP (?)       ;Output to printer
  182. BIOSAUXIN       DB      3 DUP (?)       ;Get byte from auxilliary
  183. BIOSAUXOUT      DB      3 DUP (?)       ;Output byte to auxilliary
  184. BIOSREAD        DB      3 DUP (?)       ;Disk read
  185. BIOSWRITE       DB      3 DUP (?)       ;Disk write
  186. BIOSDSKCHG      DB      3 DUP (?)       ;Dsik-change status
  187. BIOSSETDATE     DB      3 DUP (?)       ;Set date
  188. BIOSSETTIME     DB      3 DUP (?)       ;Set time
  189. BIOSGETTIME     DB      3 DUP (?)       ;Get time and date
  190. BIOSFLUSH       DB      3 DUP (?)       ;Clear console input buffer
  191. BIOSMAPDEV      DB      3 DUP (?)       ;Dynamic disk table mapper
  192.  
  193. SEGBIOS ENDS
  194. ; Location of user registers relative user stack pointer
  195.  
  196. STKPTRS STRUC
  197. AXSAVE  DW      ?
  198. BXSAVE  DW      ?
  199. CXSAVE  DW      ?
  200. DXSAVE  DW      ?
  201. SISAVE  DW      ?
  202. DISAVE  DW      ?
  203. BPSAVE  DW      ?
  204. DSSAVE  DW      ?
  205. ESSAVE  DW      ?
  206. IPSAVE  DW      ?
  207. CSSAVE  DW      ?
  208. FSAVE   DW      ?
  209. STKPTRS ENDS
  210.  
  211. ; Start of code
  212.  
  213. CODE    SEGMENT
  214. ASSUME  CS:DOSGROUP,DS:DOSGROUP,ES:DOSGROUP,SS:DOSGROUP
  215.  
  216.         ORG     0
  217. CODSTRT EQU     $
  218.         JMP     DOSINIT
  219.  
  220. ESCCHAR DB      ESCCH   ;Lead-in character for escape sequences
  221. ESCTAB:
  222.         IF      NOT IBM
  223.         DB      "S"     ;Copy one char
  224.         DB      "V"     ;Skip one char
  225.         DB      "T"     ;Copy to char
  226.         DB      "W"     ;Skip to char
  227.         DB      "U"     ;Copy line
  228.         DB      "E"     ;Kill line (no change in template)
  229.         DB      "J"     ;Reedit line (new template)
  230.         DB      "D"     ;Backspace
  231.         DB      "P"     ;Enter insert mode
  232.         DB      "Q"     ;Exit insert mode
  233.         DB      "R"     ;Escape character
  234.         DB      "R"     ;End of table
  235.         ENDIF
  236.         IF      IBM
  237.         DB      64      ;Crtl-Z - F6
  238.         DB      77      ;Copy one char - -->
  239.         DB      59      ;Copy one char - F1
  240.         DB      83      ;Skip one char - DEL
  241.         DB      60      ;Copy to char - F2
  242.         DB      62      ;Skip to char - F4
  243.         DB      61      ;Copy line - F3
  244.         DB      61      ;Kill line (no change to template ) - Not used
  245.         DB      63      ;Reedit line (new template) - F5
  246.         DB      75      ;Backspace - <--
  247.         DB      82      ;Enter insert mode - INS (toggle)
  248.         DB      65      ;Escape character - F7
  249.         DB      65      ;End of table
  250.         ENDIF
  251.  
  252. ESCTABLEN EQU   $-ESCTAB
  253.         IF      NOT IBM
  254. HEADER  DB      13,10,"MS-DOS version 1.25"
  255.         IF      HIGHMEM
  256.         DB      "H"
  257.         ENDIF
  258.         IF      DSKTEST
  259.         DB      "D"
  260.         ENDIF
  261.  
  262.         DB      13,10
  263.         DB      "Copyright 1981,82 Microsoft, Inc.",13,10,"$"
  264.         ENDIF
  265.  
  266. QUIT:
  267.         MOV     AH,0
  268.         JMP     SHORT SAVREGS
  269.  
  270. COMMAND: ;Interrupt call entry point
  271.         CMP     AH,MAXCOM
  272.         JBE     SAVREGS
  273. BADCALL:
  274.         MOV     AL,0
  275. IRET:   IRET
  276.  
  277. ENTRY:  ;System call entry point and dispatcher
  278.         POP     AX              ;IP from the long call at 5
  279.         POP     AX              ;Segment from the long call at 5
  280.         POP     CS:[TEMP]       ;IP from the CALL 5
  281.         PUSHF                   ;Start re-ordering the stack
  282.         CLI
  283.         PUSH    AX              ;Save segment
  284.         PUSH    CS:[TEMP]       ;Stack now ordered as if INT had been used
  285.         CMP     CL,MAXCALL      ;This entry point doesn't get as many calls
  286.         JA      BADCALL
  287.         MOV     AH,CL
  288. SAVREGS:
  289.         PUSH    ES
  290.         PUSH    DS
  291.         PUSH    BP
  292.         PUSH    DI
  293.         PUSH    SI
  294.         PUSH    DX
  295.         PUSH    CX
  296.         PUSH    BX
  297.         PUSH    AX
  298.  
  299.         IF      DSKTEST
  300.         MOV     AX,CS:[SPSAVE]
  301.         MOV     CS:[NSP],AX
  302.         MOV     AX,CS:[SSSAVE]
  303.         MOV     CS:[NSS],AX
  304.         POP     AX
  305.         PUSH    AX
  306.         ENDIF
  307.  
  308.         MOV     CS:[SPSAVE],SP
  309.         MOV     CS:[SSSAVE],SS
  310.         MOV     SP,CS
  311.         MOV     SS,SP
  312. REDISP:
  313.         MOV     SP,OFFSET DOSGROUP:IOSTACK
  314.         STI                     ;Stack OK now
  315.         MOV     BL,AH
  316.         MOV     BH,0
  317.         SHL     BX,1
  318.         CLD
  319.         CMP     AH,12
  320.         JLE     SAMSTK
  321.         MOV     SP,OFFSET DOSGROUP:DSKSTACK
  322. SAMSTK:
  323.         CALL    CS:[BX+DISPATCH]
  324. LEAVE:
  325.         CLI
  326.         MOV     SP,CS:[SPSAVE]
  327.         MOV     SS,CS:[SSSAVE]
  328.         MOV     BP,SP
  329.         MOV     BYTE PTR [BP.AXSAVE],AL
  330.  
  331.         IF      DSKTEST
  332.         MOV     AX,CS:[NSP]
  333.         MOV     CS:[SPSAVE],AX
  334.         MOV     AX,CS:[NSS]
  335.         MOV     CS:[SSSAVE],AX
  336.         ENDIF
  337.  
  338.         POP     AX
  339.         POP     BX
  340.         POP     CX
  341.         POP     DX
  342.         POP     SI
  343.         POP     DI
  344.         POP     BP
  345.         POP     DS
  346.         POP     ES
  347.         IRET
  348. ; Standard Functions
  349. DISPATCH DW     ABORT           ;0
  350.         DW      CONIN
  351.         DW      CONOUT
  352.         DW      READER
  353.         DW      PUNCH
  354.         DW      LIST            ;5
  355.         DW      RAWIO
  356.         DW      RAWINP
  357.         DW      IN
  358.         DW      PRTBUF
  359.         DW      BUFIN           ;10
  360.         DW      CONSTAT
  361.         DW      FLUSHKB
  362.         DW      DSKRESET
  363.         DW      SELDSK
  364.         DW      OPEN            ;15
  365.         DW      CLOSE
  366.         DW      SRCHFRST
  367.         DW      SRCHNXT
  368.         DW      DELETE
  369.         DW      SEQRD           ;20
  370.         DW      SEQWRT
  371.         DW      CREATE
  372.         DW      RENAME
  373.         DW      INUSE
  374.         DW      GETDRV          ;25
  375.         DW      SETDMA
  376.         DW      GETFATPT
  377.         DW      GETFATPTDL
  378.         DW      GETRDONLY
  379.         DW      SETATTRIB       ;30
  380.         DW      GETDSKPT
  381.         DW      USERCODE
  382.         DW      RNDRD
  383.         DW      RNDWRT
  384.         DW      FILESIZE        ;35
  385.         DW      SETRNDREC
  386. ; Extended Functions
  387.         DW      SETVECT
  388.         DW      NEWBASE
  389.         DW      BLKRD
  390.         DW      BLKWRT          ;40
  391.         DW      MAKEFCB
  392.         DW      GETDATE
  393.         DW      SETDATE
  394.         DW      GETTIME
  395.         DW      SETTIME         ;45
  396.         DW      VERIFY
  397.  
  398. INUSE:
  399. GETIO:
  400. SETIO:
  401. GETRDONLY:
  402. SETATTRIB:
  403. USERCODE:
  404.         MOV     AL,0
  405.         RET
  406.  
  407. VERIFY:
  408.         AND     AL,1
  409.         MOV     CS:VERFLG,AL
  410.         RET
  411.  
  412. FLUSHKB:
  413.         PUSH    AX
  414.         CALL    FAR PTR BIOSFLUSH
  415.         POP     AX
  416.         MOV     AH,AL
  417.         CMP     AL,1
  418.         JZ      REDISPJ
  419.         CMP     AL,6
  420.         JZ      REDISPJ
  421.         CMP     AL,7
  422.         JZ      REDISPJ
  423.         CMP     AL,8
  424.         JZ      REDISPJ
  425.         CMP     AL,10
  426.         JZ      REDISPJ
  427.         MOV     AL,0
  428.         RET
  429.  
  430. REDISPJ:JMP     REDISP
  431.  
  432. READER:
  433. AUXIN:
  434.         CALL    STATCHK
  435.         CALL    FAR PTR BIOSAUXIN
  436.         RET
  437.  
  438. PUNCH:
  439.         MOV     AL,DL
  440. AUXOUT:
  441.         PUSH    AX
  442.         CALL    STATCHK
  443.         POP     AX
  444.         CALL    FAR PTR BIOSAUXOUT
  445.         RET
  446.  
  447.  
  448. UNPACK:
  449.  
  450. ; Inputs:
  451. ;       DS = CS
  452. ;       BX = Cluster number
  453. ;       BP = Base of drive parameters
  454. ;       SI = Pointer to drive FAT
  455. ; Outputs:
  456. ;       DI = Contents of FAT for given cluster
  457. ;       Zero set means DI=0 (free cluster)
  458. ; No other registers affected. Fatal error if cluster too big.
  459.  
  460.         CMP     BX,[BP.MAXCLUS]
  461.         JA      HURTFAT
  462.         LEA     DI,[SI+BX]
  463.         SHR     BX,1
  464.         MOV     DI,[DI+BX]
  465.         JNC     HAVCLUS
  466.         SHR     DI,1
  467.         SHR     DI,1
  468.         SHR     DI,1
  469.         SHR     DI,1
  470.         STC
  471. HAVCLUS:
  472.         RCL     BX,1
  473.         AND     DI,0FFFH
  474.         RET
  475. HURTFAT:
  476.         PUSH    AX
  477.         MOV     AH,80H          ;Signal Bad FAT to INT 24H handler
  478.         MOV     DI,0FFFH        ;In case INT 24H returns (it shouldn't)
  479.         CALL    FATAL
  480.         POP     AX              ;Try to ignore bad FAT
  481.         RET
  482.  
  483.  
  484. PACK:
  485.  
  486. ; Inputs:
  487. ;       DS = CS
  488. ;       BX = Cluster number
  489. ;       DX = Data
  490. ;       SI = Pointer to drive FAT
  491. ; Outputs:
  492. ;       The data is stored in the FAT at the given cluster.
  493. ;       BX,DX,DI all destroyed
  494. ;       No other registers affected
  495.  
  496.         MOV     DI,BX
  497.         SHR     BX,1
  498.         ADD     BX,SI
  499.         ADD     BX,DI
  500.         SHR     DI,1
  501.         MOV     DI,[BX]
  502.         JNC     ALIGNED
  503.         SHL     DX,1
  504.         SHL     DX,1
  505.         SHL     DX,1
  506.         SHL     DX,1
  507.         AND     DI,0FH
  508.         JMP     SHORT PACKIN
  509. ALIGNED:
  510.         AND     DI,0F000H
  511. PACKIN:
  512.         OR      DI,DX
  513.         MOV     [BX],DI
  514.         RET
  515.  
  516. DEVNAME:
  517.         MOV     SI,OFFSET DOSGROUP:IONAME       ;List of I/O devices with file names
  518.         MOV     BH,NUMDEV               ;BH = number of device names
  519. LOOKIO:
  520.         MOV     DI,OFFSET DOSGROUP:NAME1
  521.         MOV     CX,4                    ;All devices are 4 letters
  522.         REPE    CMPSB                   ;Check for name in list
  523.         JZ      IOCHK                   ;If first 3 letters OK, check for the rest
  524.         ADD     SI,CX                   ;Point to next device name
  525.         DEC     BH
  526.         JNZ     LOOKIO
  527. CRET:
  528.         STC                             ;Not found
  529.         RET
  530.  
  531. IOCHK:
  532.         IF      IBM
  533.         CMP     BH,NUMDEV       ;Is it the first device?
  534.         JNZ     NOTCOM1
  535.         MOV     BH,2            ;Make it the same as AUX
  536. NOTCOM1:
  537.         ENDIF
  538.         NEG     BH
  539.         MOV     CX,2            ;Check rest of name but not extension
  540.         MOV     AX,2020H
  541.         REPE    SCASW           ;Make sure rest of name is blanks
  542.         JNZ     CRET
  543. RET1:   RET                     ;Zero set so CREATE works
  544.  
  545. GETFILE:
  546. ; Same as GETNAME except ES:DI points to FCB on successful return
  547.         CALL    MOVNAME
  548.         JC      RET1
  549.         PUSH    DX
  550.         PUSH    DS
  551.         CALL    FINDNAME
  552.         POP     ES
  553.         POP     DI
  554. RET2:   RET
  555.  
  556.  
  557. GETNAME:
  558.  
  559. ; Inputs:
  560. ;       DS,DX point to FCB
  561. ; Function:
  562. ;       Find file name in disk directory. First byte is
  563. ;       drive number (0=current disk). "?" matches any
  564. ;       character.
  565. ; Outputs:
  566. ;       Carry set if file not found
  567. ;       ELSE
  568. ;       Zero set if attributes match (always except when creating)
  569. ;       BP = Base of drive parameters
  570. ;       DS = CS
  571. ;       ES = CS
  572. ;       BX = Pointer into directory buffer
  573. ;       SI = Pointer to First Cluster field in directory entry
  574. ;       [DIRBUF] has directory record with match
  575. ;       [NAME1] has file name
  576. ; All other registers destroyed.
  577.  
  578.         CALL    MOVNAME
  579.         JC      RET2            ;Bad file name?
  580. FINDNAME:
  581.         MOV     AX,CS
  582.         MOV     DS,AX
  583.         CALL    DEVNAME
  584.         JNC     RET2
  585.         CALL    STARTSRCH
  586. CONTSRCH:
  587.         CALL    GETENTRY
  588.         JC      RET2
  589. SRCH:
  590.         MOV     AH,BYTE PTR [BX]
  591.         OR      AH,AH                   ;End of directory?
  592.         JZ      FREE
  593.         CMP     AH,[DELALL]             ;Free entry?
  594.         JZ      FREE
  595.         MOV     SI,BX
  596.         MOV     DI,OFFSET DOSGROUP:NAME1
  597.         MOV     CX,11
  598. WILDCRD:
  599.         REPE    CMPSB
  600.         JZ      FOUND
  601.         CMP     BYTE PTR [DI-1],"?"
  602.         JZ      WILDCRD
  603. NEXTENT:
  604.         CALL    NEXTENTRY
  605.         JNC     SRCH
  606. RET3:   RET
  607.  
  608. FREE:
  609.         CMP     [ENTFREE],-1            ;Found a free entry before?
  610.         JNZ     TSTALL                  ;If so, ignore this one
  611.         MOV     CX,[LASTENT]
  612.         MOV     [ENTFREE],CX
  613. TSTALL:
  614.         CMP     AH,[DELALL]             ;At end of directory?
  615.         JZ      NEXTENT                 ;No - continue search
  616.         STC                             ;Report not found
  617.         RET
  618.  
  619. FOUND:
  620. ;Check if attributes allow finding it
  621.         MOV     AH,[ATTRIB]             ;Attributes of search
  622.         NOT     AH
  623.         AND     AH,[SI]                 ;Compare with attributes of file
  624.         ADD     SI,15  
  625.         AND     AH,6                    ;Only look at bits 1 and 2
  626.         JZ      RET3
  627.         TEST    BYTE PTR [CREATING],-1  ;Pass back mismatch if creating
  628.         JZ      NEXTENT                 ;Otherwise continue searching
  629.         RET
  630.  
  631.  
  632. GETENTRY:
  633.  
  634. ; Inputs:
  635. ;       [LASTENT] has previously searched directory entry
  636. ; Function:
  637. ;       Locates next sequential directory entry in preparation for search
  638. ; Outputs:
  639. ;       Carry set if none
  640. ;       ELSE
  641. ;       AL = Current directory block
  642. ;       BX = Pointer to next directory entry in [DIRBUF]
  643. ;       DX = Pointer to first byte after end of DIRBUF
  644. ;       [LASTENT] = New directory entry number
  645.  
  646.         MOV     AX,[LASTENT]
  647.         INC     AX                      ;Start with next entry
  648.         CMP     AX,[BP.MAXENT]
  649.         JAE     NONE
  650. GETENT:
  651.         MOV     [LASTENT],AX
  652.         MOV     CL,4
  653.         SHL     AX,CL
  654.         XOR     DX,DX
  655.         SHL     AX,1
  656.         RCL     DX,1                    ;Account for overflow in last shift
  657.         MOV     BX,[BP.SECSIZ]
  658.         AND     BL,255-31               ;Must be multiple of 32
  659.         DIV     BX
  660.         MOV     BX,DX                   ;Position within sector
  661.         MOV     AH,[BP.DEVNUM]          ;AL=Directory sector no.
  662.         CMP     AX,[DIRBUFID]
  663.         JZ      HAVDIRBUF
  664.         PUSH    BX
  665.         CALL    DIRREAD
  666.         POP     BX
  667. HAVDIRBUF:
  668.         MOV     DX,OFFSET DOSGROUP:DIRBUF
  669.         ADD     BX,DX
  670.         ADD     DX,[BP.SECSIZ]
  671.         RET
  672.  
  673. NEXTENTRY:
  674.  
  675. ; Inputs:
  676. ;       Same as outputs of GETENTRY, above
  677. ; Function:
  678. ;       Update AL, BX, and [LASTENT] for next directory entry.
  679. ;       Carry set if no more.
  680.  
  681.         MOV     DI,[LASTENT]
  682.         INC     DI
  683.         CMP     DI,[BP.MAXENT]
  684.         JAE     NONE
  685.         MOV     [LASTENT],DI
  686.         ADD     BX,32
  687.         CMP     BX,DX
  688.         JB      HAVIT
  689.         INC     AL                      ;Next directory sector
  690.         PUSH    DX                      ;Save limit
  691.         CALL    DIRREAD
  692.         POP     DX
  693.         MOV     BX,OFFSET DOSGROUP:DIRBUF
  694. HAVIT:
  695.         CLC
  696.         RET
  697.  
  698. NONE:
  699.         CALL    CHKDIRWRITE
  700.         STC
  701. RET4:   RET
  702.  
  703.  
  704. DELETE: ; System call 19
  705.         CALL    MOVNAME
  706.         MOV     AL,-1
  707.         JC      RET4
  708.         MOV     AL,CS:[ATTRIB]
  709.         AND     AL,6                    ;Look only at hidden bits
  710.         CMP     AL,6                    ;Both must be set
  711.         JNZ     NOTALL
  712.         MOV     CX,11
  713.         MOV     AL,"?"
  714.         MOV     DI,OFFSET DOSGROUP:NAME1
  715.         REPE    SCASB                   ;See if name is *.*
  716.         JNZ     NOTALL
  717.         MOV     BYTE PTR CS:[DELALL],0  ;DEL *.* - flag deleting all
  718. NOTALL:
  719.         CALL    FINDNAME
  720.         MOV     AL,-1
  721.         JC      RET4
  722.         OR      BH,BH           ;Check if device name
  723.         JS      RET4            ;Can't delete I/O devices
  724. DELFILE:
  725.         MOV     BYTE PTR [DIRTYDIR],-1
  726.         MOV     AH,[DELALL]
  727.         MOV     BYTE PTR [BX],AH
  728.         MOV     BX,[SI]
  729.         MOV     SI,[BP.FAT]
  730.         OR      BX,BX
  731.         JZ      DELNXT
  732.         CMP     BX,[BP.MAXCLUS]
  733.         JA      DELNXT
  734.         CALL    RELEASE
  735. DELNXT:
  736.         CALL    CONTSRCH
  737.         JNC     DELFILE
  738.         CALL    FATWRT
  739.         CALL    CHKDIRWRITE
  740.         XOR     AL,AL
  741.         RET
  742.  
  743.  
  744. RENAME: ;System call 23
  745.         CALL    MOVNAME
  746.         JC      ERRET
  747.         ADD     SI,5
  748.         MOV     DI,OFFSET DOSGROUP:NAME2
  749.         CALL    LODNAME
  750.         JC      ERRET           ;Report error if second name invalid
  751.         CALL    FINDNAME
  752.         JC      ERRET
  753.         OR      BH,BH           ;Check if I/O device name
  754.         JS      ERRET           ;If so, can't rename it
  755.         MOV     SI,OFFSET DOSGROUP:NAME1
  756.         MOV     DI,OFFSET DOSGROUP:NAME3
  757.         MOV     CX,6            ;6 words (12 bytes)--include attribute byte
  758.         REP     MOVSW           ;Copy name to search for
  759. RENFIL:
  760.         MOV     DI,OFFSET DOSGROUP:NAME1
  761.         MOV     SI,OFFSET DOSGROUP:NAME2
  762.         MOV     CX,11
  763. NEWNAM:
  764.         LODSB
  765.         CMP     AL,"?"
  766.         JNZ     NOCHG
  767.         MOV     AL,[BX]
  768. NOCHG:
  769.         STOSB
  770.         INC     BX
  771.         LOOP    NEWNAM
  772.         MOV     BYTE PTR [DI],6 ;Stop duplicates with any attributes
  773.         CALL    DEVNAME         ;Check if giving it a device name
  774.         JNC     RENERR
  775.         PUSH    [LASTENT]       ;Save position of match
  776.         MOV     [LASTENT],-1    ;Search entire directory for duplicate
  777.         CALL    CONTSRCH        ;See if new name already exists
  778.         POP     AX
  779.         JNC     RENERR                  ;Error if found
  780.         CALL    GETENT                  ;Re-read matching entry
  781.         MOV     DI,BX
  782.         MOV     SI,OFFSET DOSGROUP:NAME1
  783.         MOV     CX,5
  784.         MOVSB
  785.         REP     MOVSW                   ;Replace old name with new one
  786.         MOV     BYTE PTR [DIRTYDIR],-1  ;Flag change in directory
  787.         MOV     SI,OFFSET DOSGROUP:NAME3
  788.         MOV     DI,OFFSET DOSGROUP:NAME1
  789.         MOV     CX,6                    ;Include attribute byte
  790.         REP     MOVSW                   ;Copy name back into search buffer
  791.         CALL    CONTSRCH
  792.         JNC     RENFIL
  793.         CALL    CHKDIRWRITE
  794.         XOR     AL,AL
  795.         RET
  796.  
  797. RENERR:
  798.         CALL    CHKDIRWRITE
  799. ERRET:
  800.         MOV     AL,-1
  801. RET5:   RET
  802.  
  803.  
  804. MOVNAME:
  805.  
  806. ; Inputs:
  807. ;       DS, DX point to FCB or extended FCB
  808. ; Outputs:
  809. ;       DS:DX point to normal FCB
  810. ;       ES = CS
  811. ;       If file name OK:
  812. ;       BP has base of driver parameters
  813. ;       [NAME1] has name in upper case
  814. ; All registers except DX destroyed
  815. ; Carry set if bad file name or drive
  816.  
  817.         MOV     CS:WORD PTR [CREATING],0E500H   ;Not creating, not DEL *.*
  818.         MOV     AX,CS
  819.         MOV     ES,AX
  820.         MOV     DI,OFFSET DOSGROUP:NAME1
  821.         MOV     SI,DX
  822.         LODSB
  823.         MOV     CS:[EXTFCB],AL  ;Set flag if extended FCB in use
  824.         MOV     AH,0            ;Set default attributes
  825.         CMP     AL,-1           ;Is it an extended FCB?
  826.         JNZ     HAVATTRB
  827.         ADD     DX,7            ;Adjust to point to normal FCB
  828.         ADD     SI,6            ;Point to drive select byte
  829.         MOV     AH,[SI-1]       ;Get attribute byte
  830.         LODSB           ;Get drive select byte
  831. HAVATTRB:
  832.         MOV     CS:[ATTRIB],AH  ;Save attributes
  833.         CALL    GETTHISDRV
  834. LODNAME:
  835. ; This entry point copies a file name from DS,SI
  836. ; to ES,DI converting to upper case.
  837.         CMP     BYTE PTR [SI]," "       ;Don't allow blank as first letter
  838.         STC                     ;In case of error
  839.         JZ      RET5
  840.         MOV     CX,11
  841. MOVCHK:
  842.         CALL    GETLET
  843.         JB      RET5
  844.         JNZ     STOLET          ;Is it a delimiter?
  845.         CMP     AL," "          ;This is the only delimiter allowed
  846.         STC                     ;In case of error
  847.         JNZ     RET5
  848. STOLET:
  849.         STOSB
  850.         LOOP    MOVCHK
  851.         CLC                     ;Got through whole name - no error
  852. RET6:   RET
  853.  
  854. GETTHISDRV:
  855.         CMP     CS:[NUMDRV],AL
  856.         JC      RET6
  857.         DEC     AL
  858.         JNS     PHYDRV
  859.         MOV     AL,CS:[CURDRV]
  860. PHYDRV:
  861.         MOV     CS:[THISDRV],AL
  862.         RET
  863.        
  864.  
  865. OPEN:   ;System call 15
  866.         CALL    GETFILE
  867. DOOPEN:
  868. ; Enter here to perform OPEN on file already found
  869. ; in directory. DS=CS, BX points to directory
  870. ; entry in DIRBUF, SI points to First Cluster field, and
  871. ; ES:DI point to the FCB to be opened. This entry point
  872. ; is used by CREATE.
  873.         JC      ERRET
  874.         OR      BH,BH           ;Check if file is I/O device
  875.         JS      OPENDEV         ;Special handler if so
  876.         MOV     AL,[THISDRV]
  877.         INC     AX
  878.         STOSB
  879.         XOR     AX,AX
  880.         IF      ZEROEXT
  881.         ADD     DI,11
  882.         STOSW                   ;Zero low byte of extent field if IBM only
  883.         ENDIF
  884.         IF      NOT ZEROEXT
  885.         ADD     DI,12           ;Point to high half of CURRENT BLOCK field
  886.         STOSB                   ;Set it to zero (CP/M programs set low byte)
  887.         ENDIF
  888.         MOV     AL,128          ;Default record size
  889.         STOSW                   ;Set record size
  890.         LODSW                   ;Get starting cluster
  891.         MOV     DX,AX           ;Save it for the moment
  892.         MOVSW                   ;Transfer size to FCB
  893.         MOVSW
  894.         MOV     AX,[SI-8]       ;Get date
  895.         STOSW                   ;Save date in FCB
  896.         MOV     AX,[SI-10]      ;Get time
  897.         STOSW                   ;Save it in FCB
  898.         MOV     AL,[BP.DEVNUM]
  899.         OR      AL,40H
  900.         STOSB
  901.         MOV     AX,DX           ;Restore starting cluster
  902.         STOSW                   ; first cluster
  903.         STOSW                   ; last cluster accessed
  904.         XOR     AX,AX
  905.         STOSW                   ; position of last cluster
  906.         RET
  907.  
  908.  
  909. OPENDEV:
  910.         ADD     DI,13           ;point to 2nd half of extent field
  911.         XOR     AX,AX
  912.         STOSB                   ;Set it to zero
  913.         MOV     AL,128
  914.         STOSW                   ;Set record size to 128
  915.         XOR     AX,AX
  916.         STOSW
  917.         STOSW                   ;Set current size to zero
  918.         CALL    DATE16
  919.         STOSW                   ;Date is todays
  920.         XCHG    AX,DX
  921.         STOSW                   ;Use current time
  922.         MOV     AL,BH           ;Get device number
  923.         STOSB
  924.         XOR     AL,AL           ;No error
  925.         RET
  926. FATERR:
  927.         XCHG    AX,DI           ;Put error code in DI
  928.         MOV     AH,2            ;While trying to read FAT
  929.         MOV     AL,[THISDRV]    ;Tell which drive
  930.         CALL    FATAL1
  931.         JMP     SHORT FATREAD
  932. STARTSRCH:
  933.         MOV     AX,-1
  934.         MOV     [LASTENT],AX
  935.         MOV     [ENTFREE],AX
  936. FATREAD:
  937.  
  938. ; Inputs:
  939. ;       DS = CS
  940. ; Function:
  941. ;       If disk may have been changed, FAT is read in and buffers are
  942. ;       flagged invalid. If not, no action is taken.
  943. ; Outputs:
  944. ;       BP = Base of drive parameters
  945. ;       Carry set if invalid drive returned by MAPDEV
  946. ; All other registers destroyed
  947.  
  948.         MOV     AL,[THISDRV]
  949.         XOR     AH,AH           ;Set default response to zero & clear carry
  950.         CALL    FAR PTR BIOSDSKCHG      ;See what BIOS has to say
  951.         JC      FATERR
  952.         CALL    GETBP
  953.         MOV     AL,[THISDRV]    ;Use physical unit number
  954.         MOV     SI,[BP.FAT]
  955.         OR      AH,[SI-1]       ;Dirty byte for FAT
  956.         JS      NEWDSK          ;If either say new disk, then it's so
  957.         JNZ     MAPDRV
  958.         MOV     AH,1
  959.         CMP     AX,WORD PTR [BUFDRVNO]  ;Does buffer have dirty sector of this drive?
  960.         JZ      MAPDRV
  961. NEWDSK:
  962.         CMP     AL,[BUFDRVNO]   ;See if buffer is for this drive
  963.         JNZ     BUFOK           ;If not, don't touch it
  964.         MOV     [BUFSECNO],0    ;Flag buffers invalid
  965.         MOV     WORD PTR [BUFDRVNO],00FFH
  966. BUFOK:
  967.         MOV     [DIRBUFID],-1
  968.         CALL    FIGFAT
  969. NEXTFAT:
  970.         PUSH    AX
  971.         CALL    DSKREAD
  972.         POP     AX
  973.         JC      BADFAT
  974.         SUB     AL,[BP.FATCNT]
  975.         JZ      NEWFAT
  976.         CALL    FATWRT
  977. NEWFAT:
  978.         MOV     SI,[BP.FAT]
  979.         MOV     AL,[BP.DEVNUM]
  980.         MOV     AH,[SI]         ;Get first byte of FAT
  981.         OR      AH,0F8H         ;Put in range
  982.         CALL    FAR PTR BIOSMAPDEV
  983.         MOV     AH,0
  984.         MOV     [SI-2],AX       ;Set device no. and reset dirty bit
  985. MAPDRV:
  986.         MOV     AL,[SI-2]       ;Get device number
  987. GETBP:
  988.         MOV     BP,[DRVTAB]     ;Just in case drive isn't valid
  989.         AND     AL,3FH          ;Mask out dirty bit
  990.         CMP     AL,[NUMIO]
  991.         CMC
  992.         JC      RET7
  993.         PUSH    AX
  994.         MOV     AH,DPBSIZ
  995.         MUL     AH
  996.         ADD     BP,AX
  997.         POP     AX
  998. RET7:   RET
  999.  
  1000. BADFAT:
  1001.         MOV     CX,DI
  1002.         ADD     DX,CX
  1003.         DEC     AL
  1004.         JNZ     NEXTFAT
  1005.         CALL    FIGFAT                          ;Reset registers
  1006.         CALL    DREAD                           ;Try first FAT once more
  1007.         JMP     SHORT NEWFAT
  1008.  
  1009. OKRET1:
  1010.         MOV     AL,0
  1011.         RET
  1012.  
  1013. CLOSE:  ;System call 16
  1014.         MOV     DI,DX
  1015.         CMP     BYTE PTR [DI],-1                ;Check for extended FCB
  1016.         JNZ     NORMFCB3
  1017.         ADD     DI,7
  1018. NORMFCB3:
  1019.         TEST    BYTE PTR [DI.DEVID],0C0H        ;Allow only dirty files
  1020.         JNZ     OKRET1                          ;can't close if I/O device, or not writen
  1021.         MOV     AL,[DI]                         ;Get physical unit number
  1022.         DEC     AL                              ;Make zero = drive A
  1023.         MOV     AH,1                            ;Look for dirty buffer
  1024.         CMP     AX,CS:WORD PTR [BUFDRVNO]
  1025.         JNZ     FNDDIR
  1026. ;Write back dirty buffer if on same drive
  1027.         PUSH    DX
  1028.         PUSH    DS
  1029.         PUSH    CS
  1030.         POP     DS
  1031.         MOV     BYTE PTR [DIRTYBUF],0
  1032.         MOV     BX,[BUFFER]
  1033.         MOV     CX,1
  1034.         MOV     DX,[BUFSECNO]
  1035.         MOV     BP,[BUFDRVBP]
  1036.         CALL    DWRITE
  1037.         POP     DS
  1038.         POP     DX
  1039. FNDDIR:
  1040.         CALL    GETFILE
  1041. BADCLOSEJ:
  1042.         JC      BADCLOSE
  1043.         MOV     CX,ES:[DI.FIRCLUS]
  1044.         MOV     [SI],CX
  1045.         MOV     DX,ES:WORD PTR [DI.FILSIZ]
  1046.         MOV     [SI+2],DX
  1047.         MOV     DX,ES:WORD PTR [DI.FILSIZ+2]
  1048.         MOV     [SI+4],DX
  1049.         MOV     DX,ES:[DI.FDATE]
  1050.         MOV     [SI-2],DX
  1051.         MOV     DX,ES:[DI.FTIME]
  1052.         MOV     [SI-4],DX
  1053.         CALL    DIRWRITE
  1054.  
  1055. CHKFATWRT:
  1056. ; Do FATWRT only if FAT is dirty and uses same I/O driver
  1057.         MOV     SI,[BP.FAT]
  1058.         MOV     AL,[BP.DEVNUM]
  1059.         MOV     AH,1
  1060.         CMP     [SI-2],AX       ;See if FAT dirty and uses same driver
  1061.         JNZ     OKRET
  1062.  
  1063. FATWRT:
  1064.  
  1065. ; Inputs:
  1066. ;       DS = CS
  1067. ;       BP = Base of drive parameter table
  1068. ; Function:
  1069. ;       Write the FAT back to disk and reset FAT
  1070. ;       dirty bit.
  1071. ; Outputs:
  1072. ;       AL = 0
  1073. ;       BP unchanged
  1074. ; All other registers destroyed
  1075.  
  1076.         CALL    FIGFAT
  1077.         MOV     BYTE PTR [BX-1],0
  1078. EACHFAT:
  1079.         PUSH    DX
  1080.         PUSH    CX
  1081.         PUSH    BX
  1082.         PUSH    AX
  1083.         CALL    DWRITE
  1084.         POP     AX
  1085.         POP     BX
  1086.         POP     CX
  1087.         POP     DX
  1088.         ADD     DX,CX
  1089.         DEC     AL
  1090.         JNZ     EACHFAT
  1091. OKRET:
  1092.         MOV     AL,0
  1093.         RET
  1094.  
  1095. BADCLOSE:
  1096.         MOV     SI,[BP.FAT]
  1097.         MOV     BYTE PTR [SI-1],0
  1098.         MOV     AL,-1
  1099.         RET
  1100.  
  1101.  
  1102. FIGFAT:
  1103. ; Loads registers with values needed to read or
  1104. ; write a FAT.
  1105.         MOV     AL,[BP.FATCNT]
  1106.         MOV     BX,[BP.FAT]
  1107.         MOV     CL,[BP.FATSIZ]  ;No. of records occupied by FAT
  1108.         MOV     CH,0
  1109.         MOV     DX,[BP.FIRFAT]  ;Record number of start of FATs
  1110.         RET
  1111.  
  1112.  
  1113. DIRCOMP:
  1114. ; Prepare registers for directory read or write
  1115.         CBW
  1116.         ADD     AX,[BP.FIRDIR]
  1117.         MOV     DX,AX
  1118.         MOV     BX,OFFSET DOSGROUP:DIRBUF
  1119.         MOV     CX,1
  1120.         RET
  1121.  
  1122.  
  1123. CREATE: ;System call 22
  1124.         CALL    MOVNAME
  1125.         JC      ERRET3
  1126.         MOV     DI,OFFSET DOSGROUP:NAME1
  1127.         MOV     CX,11
  1128.         MOV     AL,"?"
  1129.         REPNE   SCASB
  1130.         JZ      ERRET3
  1131.         MOV     CS:BYTE PTR [CREATING],-1
  1132.         PUSH    DX
  1133.         PUSH    DS
  1134.         CALL    FINDNAME
  1135.         JNC     EXISTENT
  1136.         MOV     AX,[ENTFREE]    ;First free entry found in FINDNAME
  1137.         CMP     AX,-1
  1138.         JZ      ERRPOP
  1139.         CALL    GETENT          ;Point at that free entry
  1140.         JMP     SHORT FREESPOT
  1141. ERRPOP:
  1142.         POP     DS
  1143.         POP     DX
  1144. ERRET3:
  1145.         MOV     AL,-1
  1146.         RET
  1147.  
  1148. EXISTENT:
  1149.         JNZ     ERRPOP          ;Error if attributes don't match
  1150.         OR      BH,BH           ;Check if file is I/O device
  1151.         JS      OPENJMP         ;If so, no action
  1152.         MOV     CX,[SI]         ;Get pointer to clusters
  1153.         JCXZ    FREESPOT
  1154.         CMP     CX,[BP.MAXCLUS]
  1155.         JA      FREESPOT
  1156.         PUSH    BX
  1157.         MOV     BX,CX
  1158.         MOV     SI,[BP.FAT]
  1159.         CALL    RELEASE         ;Free any data already allocated
  1160.         CALL    FATWRT
  1161.         POP     BX
  1162. FREESPOT:
  1163.         MOV     DI,BX
  1164.         MOV     SI,OFFSET DOSGROUP:NAME1
  1165.         MOV     CX,5
  1166.         MOVSB
  1167.         REP     MOVSW
  1168.         MOV     AL,[ATTRIB]
  1169.         STOSB
  1170.         XOR     AX,AX
  1171.         MOV     CL,5
  1172.         REP     STOSW
  1173.         CALL    DATE16
  1174.         XCHG    AX,DX
  1175.         STOSW
  1176.         XCHG    AX,DX
  1177.         STOSW
  1178.         XOR     AX,AX
  1179.         PUSH    DI
  1180.         MOV     CL,6
  1181. SMALLENT:
  1182.         REP     STOSB
  1183.         PUSH    BX
  1184.         CALL    DIRWRITE
  1185.         POP     BX
  1186.         POP     SI
  1187. OPENJMP:
  1188.         CLC                     ;Clear carry so OPEN won't fail
  1189.         POP     ES
  1190.         POP     DI
  1191.         JMP     DOOPEN
  1192.  
  1193.  
  1194. DIRREAD:
  1195.  
  1196. ; Inputs:
  1197. ;       DS = CS
  1198. ;       AL = Directory block number
  1199. ;       BP = Base of drive parameters
  1200. ; Function:
  1201. ;       Read the directory block into DIRBUF.
  1202. ; Outputs:
  1203. ;       AX,BP unchanged
  1204. ; All other registers destroyed.
  1205.  
  1206.         PUSH    AX
  1207.         CALL    CHKDIRWRITE
  1208.         POP     AX
  1209.         PUSH    AX
  1210.         MOV     AH,[BP.DEVNUM]
  1211.         MOV     [DIRBUFID],AX
  1212.         CALL    DIRCOMP
  1213.         CALL    DREAD
  1214.         POP     AX
  1215. RET8:   RET
  1216.  
  1217.  
  1218. DREAD:
  1219.  
  1220. ; Inputs:
  1221. ;       BX,DS = Transfer address
  1222. ;       CX = Number of sectors
  1223. ;       DX = Absolute record number
  1224. ;       BP = Base of drive parameters
  1225. ; Function:
  1226. ;       Calls BIOS to perform disk read. If BIOS reports
  1227. ;       errors, will call HARDERR for further action.
  1228. ; BP preserved. All other registers destroyed.
  1229.  
  1230.         CALL    DSKREAD
  1231.         JNC     RET8
  1232.         MOV     CS:BYTE PTR [READOP],0
  1233.         CALL    HARDERR
  1234.         CMP     AL,1            ;Check for retry
  1235.         JZ      DREAD
  1236.         RET                     ;Ignore otherwise
  1237.  
  1238.  
  1239. HARDERR:
  1240.  
  1241. ;Hard disk error handler. Entry conditions:
  1242. ;       DS:BX = Original disk transfer address
  1243. ;       DX = Original logical sector number
  1244. ;       CX = Number of sectors to go (first one gave the error)
  1245. ;       AX = Hardware error code
  1246. ;       DI = Original sector transfer count
  1247. ;       BP = Base of drive parameters
  1248. ;       [READOP] = 0 for read, 1 for write
  1249.  
  1250.         XCHG    AX,DI           ;Error code in DI, count in AX
  1251.         SUB     AX,CX           ;Number of sectors successfully transferred
  1252.         ADD     DX,AX           ;First sector number to retry
  1253.         PUSH    DX
  1254.         MUL     [BP.SECSIZ]     ;Number of bytes transferred
  1255.         POP     DX
  1256.         ADD     BX,AX           ;First address for retry
  1257.         MOV     AH,0            ;Flag disk section in error
  1258.         CMP     DX,[BP.FIRFAT]  ;In reserved area?
  1259.         JB      ERRINT
  1260.         INC     AH              ;Flag for FAT
  1261.         CMP     DX,[BP.FIRDIR]  ;In FAT?
  1262.         JB      ERRINT
  1263.         INC     AH
  1264.         CMP     DX,[BP.FIRREC]  ;In directory?
  1265.         JB      ERRINT
  1266.         INC     AH              ;Must be in data area
  1267. ERRINT:
  1268.         SHL     AH,1            ;Make room for read/write bit
  1269.         OR      AH,CS:[READOP]
  1270. FATAL:
  1271.         MOV     AL,[BP.DRVNUM]  ;Get drive number
  1272. FATAL1:
  1273.         PUSH    BP              ;The only thing we preserve
  1274.         MOV     CS:[CONTSTK],SP
  1275.         CLI                     ;Prepare to play with stack
  1276.         MOV     SS,CS:[SSSAVE]
  1277.         MOV     SP,CS:[SPSAVE]  ;User stack pointer restored
  1278.         INT     24H             ;Fatal error interrupt vector
  1279.         MOV     CS:[SPSAVE],SP
  1280.         MOV     CS:[SSSAVE],SS
  1281.         MOV     SP,CS
  1282.         MOV     SS,SP
  1283.         MOV     SP,CS:[CONTSTK]
  1284.         STI
  1285.         POP     BP
  1286.         CMP     AL,2
  1287.         JZ      ERROR
  1288.         RET
  1289.  
  1290. DSKREAD:
  1291.         MOV     AL,[BP.DEVNUM]
  1292.         PUSH    BP
  1293.         PUSH    BX
  1294.         PUSH    CX
  1295.         PUSH    DX
  1296.         CALL    FAR PTR BIOSREAD
  1297.         POP     DX
  1298.         POP     DI
  1299.         POP     BX
  1300.         POP     BP
  1301. RET9:   RET
  1302.  
  1303.  
  1304. CHKDIRWRITE:
  1305.         TEST    BYTE PTR [DIRTYDIR],-1
  1306.         JZ      RET9
  1307.  
  1308. DIRWRITE:
  1309.  
  1310. ; Inputs:
  1311. ;       DS = CS
  1312. ;       AL = Directory block number
  1313. ;       BP = Base of drive parameters
  1314. ; Function:
  1315. ;       Write the directory block into DIRBUF.
  1316. ; Outputs:
  1317. ;       BP unchanged
  1318. ; All other registers destroyed.
  1319.  
  1320.         MOV     BYTE PTR [DIRTYDIR],0
  1321.         MOV     AL,BYTE PTR [DIRBUFID]
  1322.         CALL    DIRCOMP
  1323.  
  1324.  
  1325. DWRITE:
  1326.  
  1327. ; Inputs:
  1328. ;       BX,DS = Transfer address
  1329. ;       CX = Number of sectors
  1330. ;       DX = Absolute record number
  1331. ;       BP = Base of drive parameters
  1332. ; Function:
  1333. ;       Calls BIOS to perform disk write. If BIOS reports
  1334. ;       errors, will call HARDERR for further action.
  1335. ; BP preserved. All other registers destroyed.
  1336.  
  1337.         MOV     AL,[BP.DEVNUM]
  1338.         MOV     AH,CS:VERFLG
  1339.         PUSH    BP
  1340.         PUSH    BX
  1341.         PUSH    CX
  1342.         PUSH    DX
  1343.         CALL    FAR PTR BIOSWRITE
  1344.         POP     DX
  1345.         POP     DI
  1346.         POP     BX
  1347.         POP     BP
  1348.         JNC     RET9
  1349.         MOV     CS:BYTE PTR [READOP],1
  1350.         CALL    HARDERR
  1351.         CMP     AL,1            ;Check for retry
  1352.         JZ      DWRITE
  1353.         RET
  1354.  
  1355.  
  1356. ABORT:
  1357.         LDS     SI,CS:DWORD PTR [SPSAVE]
  1358.         MOV     DS,[SI.CSSAVE]
  1359.         XOR     AX,AX
  1360.         MOV     ES,AX
  1361.         MOV     SI,SAVEXIT
  1362.         MOV     DI,EXIT
  1363.         MOVSW
  1364.         MOVSW
  1365.         MOVSW
  1366.         MOVSW
  1367.         MOVSW
  1368.         MOVSW
  1369. ERROR:
  1370.         MOV     AX,CS
  1371.         MOV     DS,AX
  1372.         MOV     ES,AX
  1373.         CALL    WRTFATS
  1374.         XOR     AX,AX
  1375.         CLI
  1376.         MOV     SS,[SSSAVE]
  1377.         MOV     SP,[SPSAVE]
  1378.         MOV     DS,AX
  1379.         MOV     SI,EXIT
  1380.         MOV     DI,OFFSET DOSGROUP:EXITHOLD
  1381.         MOVSW
  1382.         MOVSW
  1383.         POP     AX
  1384.         POP     BX
  1385.         POP     CX
  1386.         POP     DX
  1387.         POP     SI
  1388.         POP     DI
  1389.         POP     BP
  1390.         POP     DS
  1391.         POP     ES
  1392.         STI             ;Stack OK now
  1393.         JMP     CS:DWORD PTR [EXITHOLD]
  1394.  
  1395.  
  1396. SEQRD:  ;System call 20
  1397.         CALL    GETREC
  1398.         CALL    LOAD
  1399.         JMP     SHORT FINSEQ
  1400.  
  1401. SEQWRT: ;System call 21
  1402.         CALL    GETREC
  1403.         CALL    STORE
  1404. FINSEQ:
  1405.         JCXZ    SETNREX
  1406.         ADD     AX,1
  1407.         ADC     DX,0
  1408.         JMP     SHORT SETNREX
  1409.  
  1410. RNDRD:  ;System call 33
  1411.         CALL    GETRRPOS1
  1412.         CALL    LOAD
  1413.         JMP     SHORT FINRND
  1414.  
  1415. RNDWRT: ;System call 34
  1416.         CALL    GETRRPOS1
  1417.         CALL    STORE
  1418.         JMP     SHORT FINRND
  1419.  
  1420. BLKRD:  ;System call 39
  1421.         CALL    GETRRPOS
  1422.         CALL    LOAD
  1423.         JMP     SHORT FINBLK
  1424.  
  1425. BLKWRT: ;System call 40
  1426.         CALL    GETRRPOS
  1427.         CALL    STORE
  1428. FINBLK:
  1429.         LDS     SI,DWORD PTR [SPSAVE]
  1430.         MOV     [SI.CXSAVE],CX
  1431.         JCXZ    FINRND
  1432.         ADD     AX,1
  1433.         ADC     DX,0
  1434. FINRND:
  1435.         MOV     ES:WORD PTR [DI.RR],AX
  1436.         MOV     ES:[DI.RR+2],DL
  1437.         OR      DH,DH
  1438.         JZ      SETNREX
  1439.         MOV     ES:[DI.RR+3],DH ;Save 4 byte of RECPOS only if significant
  1440. SETNREX:
  1441.         MOV     CX,AX
  1442.         AND     AL,7FH
  1443.         MOV     ES:[DI.NR],AL
  1444.         AND     CL,80H
  1445.         SHL     CX,1
  1446.         RCL     DX,1
  1447.         MOV     AL,CH
  1448.         MOV     AH,DL
  1449.         MOV     ES:[DI.EXTENT],AX
  1450.         MOV     AL,CS:[DSKERR]
  1451.         RET
  1452.  
  1453. GETRRPOS1:
  1454.         MOV     CX,1
  1455. GETRRPOS:
  1456.         MOV     DI,DX
  1457.         CMP     BYTE PTR [DI],-1
  1458.         JNZ     NORMFCB1
  1459.         ADD     DI,7
  1460. NORMFCB1:
  1461.         MOV     AX,WORD PTR [DI.RR]
  1462.         MOV     DX,WORD PTR [DI.RR+2]
  1463.         RET
  1464.  
  1465. NOFILERR:
  1466.         XOR     CX,CX
  1467.         MOV     BYTE PTR [DSKERR],4
  1468.         POP     BX
  1469.         RET
  1470.  
  1471. SETUP:
  1472.  
  1473. ; Inputs:
  1474. ;       DS:DI point to FCB
  1475. ;       DX:AX = Record position in file of disk transfer
  1476. ;       CX = Record count
  1477. ; Outputs:
  1478. ;       DS = CS
  1479. ;       ES:DI point to FCB
  1480. ;       BL = DEVID from FCB
  1481. ;       CX = No. of bytes to transfer
  1482. ;       BP = Base of drive parameters
  1483. ;       SI = FAT pointer
  1484. ;       [RECCNT] = Record count
  1485. ;       [RECPOS] = Record position in file
  1486. ;       [FCB] = DI
  1487. ;       [NEXTADD] = Displacement of disk transfer within segment
  1488. ;       [SECPOS] = Position of first sector
  1489. ;       [BYTPOS] = Byte position in file
  1490. ;       [BYTSECPOS] = Byte position in first sector
  1491. ;       [CLUSNUM] = First cluster
  1492. ;       [SECCLUSPOS] = Sector within first cluster
  1493. ;       [DSKERR] = 0 (no errors yet)
  1494. ;       [TRANS] = 0 (No transfers yet)
  1495. ;       [THISDRV] = Physical drive unit number
  1496. ; If SETUP detects no records will be transfered, it returns 1 level up
  1497. ; with CX = 0.
  1498.  
  1499.         PUSH    AX
  1500.         MOV     AL,[DI]
  1501.         DEC     AL
  1502.         MOV     CS:[THISDRV],AL
  1503.         MOV     AL,[DI.DEVID]
  1504.         MOV     SI,[DI.RECSIZ]
  1505.         OR      SI,SI
  1506.         JNZ     HAVRECSIZ
  1507.         MOV     SI,128
  1508.         MOV     [DI.RECSIZ],SI
  1509. HAVRECSIZ:
  1510.         PUSH    DS
  1511.         POP     ES              ;Set ES to DS
  1512.         PUSH    CS
  1513.         POP     DS              ;Set DS to CS
  1514.         OR      AL,AL           ;Is it a device?
  1515.         JNS     NOTDEVICE
  1516.         MOV     AL,0            ;Fake in drive 0 so we can get SP
  1517. NOTDEVICE:
  1518.         CALL    GETBP
  1519.         POP     AX
  1520.         JC      NOFILERR
  1521.         CMP     SI,64           ;Check if highest byte of RECPOS is significant
  1522.         JB      SMALREC
  1523.         MOV     DH,0            ;Ignore MSB if record >= 64 bytes
  1524. SMALREC:
  1525.         MOV     [RECCNT],CX
  1526.         MOV     WORD PTR [RECPOS],AX
  1527.         MOV     WORD PTR [RECPOS+2],DX
  1528.         MOV     [FCB],DI
  1529.         MOV     BX,[DMAADD]
  1530.         MOV     [NEXTADD],BX
  1531.         MOV     BYTE PTR [DSKERR],0
  1532.         MOV     BYTE PTR [TRANS],0
  1533.         MOV     BX,DX
  1534.         MUL     SI
  1535.         MOV     WORD PTR [BYTPOS],AX
  1536.         PUSH    DX
  1537.         MOV     AX,BX
  1538.         MUL     SI
  1539.         POP     BX
  1540.         ADD     AX,BX
  1541.         ADC     DX,0            ;Ripple carry
  1542.         JNZ     EOFERR
  1543.         MOV     WORD PTR [BYTPOS+2],AX
  1544.         MOV     DX,AX
  1545.         MOV     AX,WORD PTR [BYTPOS]
  1546.         MOV     BX,[BP.SECSIZ]
  1547.         CMP     DX,BX           ;See if divide will overflow
  1548.         JNC     EOFERR
  1549.         DIV     BX
  1550.         MOV     [SECPOS],AX
  1551.         MOV     [BYTSECPOS],DX
  1552.         MOV     DX,AX
  1553.         AND     AL,[BP.CLUSMSK]
  1554.         MOV     [SECCLUSPOS],AL
  1555.         MOV     AX,CX           ;Record count
  1556.         MOV     CL,[BP.CLUSSHFT]
  1557.         SHR     DX,CL
  1558.         MOV     [CLUSNUM],DX
  1559.         MUL     SI              ;Multiply by bytes per record
  1560.         MOV     CX,AX
  1561.         ADD     AX,[DMAADD]     ;See if it will fit in one segment
  1562.         ADC     DX,0
  1563.         JZ      OK              ;Must be less than 64K
  1564.         MOV     AX,[DMAADD]
  1565.         NEG     AX              ;Amount of room left in segment
  1566.         JNZ     PARTSEG         ;All 64K available?
  1567.         DEC     AX              ;If so, reduce by one
  1568. PARTSEG:
  1569.         XOR     DX,DX
  1570.         DIV     SI              ;How many records will fit?
  1571.         MOV     [RECCNT],AX
  1572.         MUL     SI              ;Translate that back into bytes
  1573.         MOV     BYTE PTR [DSKERR],2     ;Flag that trimming took place
  1574.         MOV     CX,AX
  1575.         JCXZ    NOROOM
  1576. OK:
  1577.         MOV     BL,ES:[DI.DEVID]
  1578.         MOV     SI,[BP.FAT]
  1579.         RET
  1580.  
  1581. EOFERR:
  1582.         MOV     BYTE PTR [DSKERR],1
  1583.         XOR     CX,CX
  1584. NOROOM:
  1585.         POP     BX              ;Kill return address
  1586.         RET
  1587.  
  1588. BREAKDOWN:
  1589.  
  1590. ;Inputs:
  1591. ;       DS = CS
  1592. ;       CX = Length of disk transfer in bytes
  1593. ;       BP = Base of drive parameters
  1594. ;       [BYTSECPOS] = Byte position witin first sector
  1595. ;Outputs:
  1596. ;       [BYTCNT1] = Bytes to transfer in first sector
  1597. ;       [SECCNT] = No. of whole sectors to transfer
  1598. ;       [BYTCNT2] = Bytes to transfer in last sector
  1599. ;AX, BX, DX destroyed. No other registers affected.
  1600.  
  1601.         MOV     AX,[BYTSECPOS]
  1602.         MOV     BX,CX
  1603.         OR      AX,AX
  1604.         JZ      SAVFIR          ;Partial first sector?
  1605.         SUB     AX,[BP.SECSIZ]
  1606.         NEG     AX              ;Max number of bytes left in first sector
  1607.         SUB     BX,AX           ;Subtract from total length
  1608.         JAE     SAVFIR
  1609.         ADD     AX,BX           ;Don't use all of the rest of the sector
  1610.         XOR     BX,BX           ;And no bytes are left
  1611. SAVFIR:
  1612.         MOV     [BYTCNT1],AX
  1613.         MOV     AX,BX
  1614.         XOR     DX,DX
  1615.         DIV     [BP.SECSIZ]     ;How many whole sectors?
  1616.         MOV     [SECCNT],AX
  1617.         MOV     [BYTCNT2],DX    ;Bytes remaining for last sector
  1618. RET10:  RET
  1619.  
  1620.  
  1621. FNDCLUS:
  1622.  
  1623. ; Inputs:
  1624. ;       DS = CS
  1625. ;       CX = No. of clusters to skip
  1626. ;       BP = Base of drive parameters
  1627. ;       SI = FAT pointer
  1628. ;       ES:DI point to FCB
  1629. ; Outputs:
  1630. ;       BX = Last cluster skipped to
  1631. ;       CX = No. of clusters remaining (0 unless EOF)
  1632. ;       DX = Position of last cluster
  1633. ; DI destroyed. No other registers affected.
  1634.  
  1635.         MOV     BX,ES:[DI.LSTCLUS]
  1636.         MOV     DX,ES:[DI.CLUSPOS]
  1637.         OR      BX,BX
  1638.         JZ      NOCLUS
  1639.         SUB     CX,DX
  1640.         JNB     FINDIT
  1641.         ADD     CX,DX
  1642.         XOR     DX,DX
  1643.         MOV     BX,ES:[DI.FIRCLUS]
  1644. FINDIT:
  1645.         JCXZ    RET10
  1646. SKPCLP:
  1647.         CALL    UNPACK
  1648.         CMP     DI,0FF8H
  1649.         JAE     RET10
  1650.         XCHG    BX,DI
  1651.         INC     DX
  1652.         LOOP    SKPCLP
  1653.         RET
  1654. NOCLUS:
  1655.         INC     CX
  1656.         DEC     DX
  1657.         RET
  1658.  
  1659.  
  1660. BUFSEC:
  1661. ; Inputs:
  1662. ;       AL = 0 if buffer must be read, 1 if no pre-read needed
  1663. ;       BP = Base of drive parameters
  1664. ;       [CLUSNUM] = Physical cluster number
  1665. ;       [SECCLUSPOS] = Sector position of transfer within cluster
  1666. ;       [BYTCNT1] = Size of transfer
  1667. ; Function:
  1668. ;       Insure specified sector is in buffer, flushing buffer before
  1669. ;       read if necessary.
  1670. ; Outputs:
  1671. ;       SI = Pointer to buffer
  1672. ;       DI = Pointer to transfer address
  1673. ;       CX = Number of bytes
  1674. ;       [NEXTADD] updated
  1675. ;       [TRANS] set to indicate a transfer will occur
  1676.  
  1677.         MOV     DX,[CLUSNUM]
  1678.         MOV     BL,[SECCLUSPOS]
  1679.         CALL    FIGREC
  1680.         MOV     [PREREAD],AL
  1681.         CMP     DX,[BUFSECNO]
  1682.         JNZ     GETSEC
  1683.         MOV     AL,[BUFDRVNO]
  1684.         CMP     AL,[THISDRV]
  1685.         JZ      FINBUF          ;Already have it?
  1686. GETSEC:
  1687.         XOR     AL,AL
  1688.         XCHG    [DIRTYBUF],AL   ;Read dirty flag and reset it
  1689.         OR      AL,AL
  1690.         JZ      RDSEC
  1691.         PUSH    DX
  1692.         PUSH    BP
  1693.         MOV     BP,[BUFDRVBP]
  1694.         MOV     BX,[BUFFER]
  1695.         MOV     CX,1
  1696.         MOV     DX,[BUFSECNO]
  1697.         CALL    DWRITE
  1698.         POP     BP
  1699.         POP     DX
  1700. RDSEC:
  1701.         TEST    BYTE PTR [PREREAD],-1
  1702.         JNZ     SETBUF
  1703.         XOR     AX,AX
  1704.         MOV     [BUFSECNO],AX           ;Set buffer valid in case of disk error
  1705.         DEC     AX
  1706.         MOV     [BUFDRVNO],AL
  1707.         MOV     BX,[BUFFER]
  1708.         MOV     CX,1
  1709.         PUSH    DX
  1710.         CALL    DREAD
  1711.         POP     DX
  1712. SETBUF:
  1713.         MOV     [BUFSECNO],DX
  1714.         MOV     AL,[THISDRV]
  1715.         MOV     [BUFDRVNO],AL
  1716.         MOV     [BUFDRVBP],BP
  1717. FINBUF:
  1718.         MOV     BYTE PTR [TRANS],1      ;A transfer is taking place
  1719.         MOV     DI,[NEXTADD]
  1720.         MOV     SI,DI
  1721.         MOV     CX,[BYTCNT1]
  1722.         ADD     SI,CX
  1723.         MOV     [NEXTADD],SI
  1724.         MOV     SI,[BUFFER]
  1725.         ADD     SI,[BYTSECPOS]
  1726.         RET
  1727.  
  1728. BUFRD:
  1729.         XOR     AL,AL           ;Pre-read necessary
  1730.         CALL    BUFSEC
  1731.         PUSH    ES
  1732.         MOV     ES,[DMAADD+2]
  1733.         SHR     CX,1
  1734.         JNC     EVENRD
  1735.         MOVSB
  1736. EVENRD:
  1737.         REP     MOVSW
  1738.         POP     ES
  1739.         RET
  1740.  
  1741. BUFWRT:
  1742.         MOV     AX,[SECPOS]
  1743.         INC     AX              ;Set for next sector
  1744.         MOV     [SECPOS],AX
  1745.         CMP     AX,[VALSEC]     ;Has sector been written before?
  1746.         MOV     AL,1
  1747.         JA      NOREAD          ;Skip preread if SECPOS>VALSEC
  1748.         MOV     AL,0
  1749. NOREAD:
  1750.         CALL    BUFSEC
  1751.         XCHG    DI,SI
  1752.         PUSH    DS
  1753.         PUSH    ES
  1754.         PUSH    CS
  1755.         POP     ES
  1756.         MOV     DS,[DMAADD+2]
  1757.         SHR     CX,1
  1758.         JNC     EVENWRT
  1759.         MOVSB
  1760. EVENWRT:
  1761.         REP     MOVSW
  1762.         POP     ES
  1763.         POP     DS
  1764.         MOV     BYTE PTR [DIRTYBUF],1
  1765.         RET
  1766.  
  1767. NEXTSEC:
  1768.         TEST    BYTE PTR [TRANS],-1
  1769.         JZ      CLRET
  1770.         MOV     AL,[SECCLUSPOS]
  1771.         INC     AL
  1772.         CMP     AL,[BP.CLUSMSK]
  1773.         JBE     SAVPOS
  1774.         MOV     BX,[CLUSNUM]
  1775.         CMP     BX,0FF8H
  1776.         JAE     NONEXT
  1777.         MOV     SI,[BP.FAT]
  1778.         CALL    UNPACK
  1779.         MOV     [CLUSNUM],DI
  1780.         INC     [LASTPOS]
  1781.         MOV     AL,0
  1782. SAVPOS:
  1783.         MOV     [SECCLUSPOS],AL
  1784. CLRET:
  1785.         CLC
  1786.         RET
  1787. NONEXT:
  1788.         STC
  1789.         RET
  1790.  
  1791. TRANBUF:
  1792.         LODSB
  1793.         STOSB
  1794.         CMP     AL,13           ;Check for carriage return
  1795.         JNZ     NORMCH
  1796.         MOV     BYTE PTR [SI],10
  1797. NORMCH:
  1798.         CMP     AL,10
  1799.         LOOPNZ  TRANBUF
  1800.         JNZ     ENDRDCON
  1801.         CALL    OUT             ;Transmit linefeed
  1802.         XOR     SI,SI
  1803.         OR      CX,CX
  1804.         JNZ     GETBUF
  1805.         OR      AL,1            ;Clear zero flag--not end of file
  1806. ENDRDCON:
  1807.         MOV     [CONTPOS],SI
  1808. ENDRDDEV:
  1809.         MOV     [NEXTADD],DI
  1810.         POP     ES
  1811.         JNZ     SETFCBJ         ;Zero set if Ctrl-Z found in input
  1812.         MOV     DI,[FCB]
  1813.         AND     ES:BYTE PTR [DI.DEVID],0FFH-40H ;Mark as no more data available
  1814. SETFCBJ:
  1815.         JMP     SETFCB
  1816.  
  1817. READDEV:
  1818.         PUSH    ES
  1819.         LES     DI,DWORD PTR [DMAADD]
  1820.         INC     BL
  1821.         JZ      READCON
  1822.         INC     BL
  1823.         JNZ     ENDRDDEV
  1824. READAUX:
  1825.         CALL    AUXIN
  1826.         STOSB
  1827.         CMP     AL,1AH
  1828.         LOOPNZ  READAUX
  1829.         JMP     SHORT ENDRDDEV
  1830.  
  1831. READCON:
  1832.         PUSH    CS
  1833.         POP     DS
  1834.         MOV     SI,[CONTPOS]
  1835.         OR      SI,SI
  1836.         JNZ     TRANBUF
  1837.         CMP     BYTE PTR [CONBUF],128
  1838.         JZ      GETBUF
  1839.         MOV     WORD PTR [CONBUF],0FF80H        ;Set up 128-byte buffer with no template
  1840. GETBUF:
  1841.         PUSH    CX
  1842.         PUSH    ES
  1843.         PUSH    DI
  1844.         MOV     DX,OFFSET DOSGROUP:CONBUF
  1845.         CALL    BUFIN           ;Get input buffer
  1846.         POP     DI
  1847.         POP     ES
  1848.         POP     CX
  1849.         MOV     SI,2 + OFFSET DOSGROUP:CONBUF
  1850.         CMP     BYTE PTR [SI],1AH       ;Check for Ctrl-Z in first character
  1851.         JNZ     TRANBUF
  1852.         MOV     AL,1AH
  1853.         STOSB
  1854.         MOV     AL,10
  1855.         CALL    OUT             ;Send linefeed
  1856.         XOR     SI,SI
  1857.         JMP     SHORT ENDRDCON
  1858.  
  1859. RDERR:
  1860.         XOR     CX,CX
  1861.         JMP     WRTERR
  1862.  
  1863. RDLASTJ:JMP     RDLAST
  1864.  
  1865. LOAD:
  1866.  
  1867. ; Inputs:
  1868. ;       DS:DI point to FCB
  1869. ;       DX:AX = Position in file to read
  1870. ;       CX = No. of records to read
  1871. ; Outputs:
  1872. ;       DX:AX = Position of last record read
  1873. ;       CX = No. of bytes read
  1874. ;       ES:DI point to FCB
  1875. ;       LSTCLUS, CLUSPOS fields in FCB set
  1876.  
  1877.         CALL    SETUP
  1878.         OR      BL,BL           ;Check for named device I/O
  1879.         JS      READDEV
  1880.         MOV     AX,ES:WORD PTR [DI.FILSIZ]
  1881.         MOV     BX,ES:WORD PTR [DI.FILSIZ+2]
  1882.         SUB     AX,WORD PTR [BYTPOS]
  1883.         SBB     BX,WORD PTR [BYTPOS+2]
  1884.         JB      RDERR
  1885.         JNZ     ENUF
  1886.         OR      AX,AX
  1887.         JZ      RDERR
  1888.         CMP     AX,CX
  1889.         JAE     ENUF
  1890.         MOV     CX,AX
  1891. ENUF:
  1892.         CALL    BREAKDOWN
  1893.         MOV     CX,[CLUSNUM]
  1894.         CALL    FNDCLUS
  1895.         OR      CX,CX
  1896.         JNZ     RDERR
  1897.         MOV     [LASTPOS],DX
  1898.         MOV     [CLUSNUM],BX
  1899.         CMP     [BYTCNT1],0
  1900.         JZ      RDMID
  1901.         CALL    BUFRD
  1902. RDMID:
  1903.         CMP     [SECCNT],0
  1904.         JZ      RDLASTJ
  1905.         CALL    NEXTSEC
  1906.         JC      SETFCB
  1907.         MOV     BYTE PTR [TRANS],1      ;A transfer is taking place
  1908. ONSEC:
  1909.         MOV     DL,[SECCLUSPOS]
  1910.         MOV     CX,[SECCNT]
  1911.         MOV     BX,[CLUSNUM]
  1912. RDLP:
  1913.         CALL    OPTIMIZE
  1914.         PUSH    DI
  1915.         PUSH    AX
  1916.         PUSH    DS
  1917.         MOV     DS,[DMAADD+2]
  1918.         PUSH    DX
  1919.         PUSH    BX
  1920.         PUSHF                   ;Save carry flag
  1921.         CALL DREAD
  1922.         POPF                    ;Restore carry flag
  1923.         POP     DI              ;Initial transfer address
  1924.         POP     AX              ;First sector transfered
  1925.         POP     DS
  1926.         JC      NOTBUFFED       ;Was one of those sectors in the buffer?
  1927.         CMP     BYTE PTR [DIRTYBUF],0   ;Is buffer dirty?
  1928.         JZ      NOTBUFFED       ;If not no problem
  1929. ;We have transfered in a sector from disk when a dirty copy of it is in the buffer.
  1930. ;We must transfer the sector from the buffer to correct memory address
  1931.         SUB     AX,[BUFSECNO]   ;How many sectors into the transfer?
  1932.         NEG     AX
  1933.         MOV     CX,[BP.SECSIZ]
  1934.         MUL     CX              ;How many bytes into the transfer?
  1935.         ADD     DI,AX
  1936.         MOV     SI,[BUFFER]
  1937.         PUSH    ES
  1938.         MOV     ES,[DMAADD+2]   ;Get disk transfer segment
  1939.         SHR     CX,1
  1940.         REP     MOVSW
  1941.         JNC     EVENMOV
  1942.         MOVSB
  1943. EVENMOV:
  1944.         POP     ES
  1945. NOTBUFFED:
  1946.         POP     CX
  1947.         POP     BX
  1948.         JCXZ    RDLAST
  1949.         CMP     BX,0FF8H
  1950.         JAE     SETFCB
  1951.         MOV     DL,0
  1952.         INC     [LASTPOS]       ;We'll be using next cluster
  1953.         JMP     SHORT RDLP
  1954.  
  1955. SETFCB:
  1956.         MOV     SI,[FCB]
  1957.         MOV     AX,[NEXTADD]
  1958.         MOV     DI,AX
  1959.         SUB     AX,[DMAADD]     ;Number of bytes transfered
  1960.         XOR     DX,DX
  1961.         MOV     CX,ES:[SI.RECSIZ]
  1962.         DIV     CX              ;Number of records
  1963.         CMP     AX,[RECCNT]     ;Check if all records transferred
  1964.         JZ      FULLREC
  1965.         MOV     BYTE PTR [DSKERR],1
  1966.         OR      DX,DX
  1967.         JZ      FULLREC         ;If remainder 0, then full record transfered
  1968.         MOV     BYTE PTR [DSKERR],3     ;Flag partial last record
  1969.         SUB     CX,DX           ;Bytes left in last record
  1970.         PUSH    ES
  1971.         MOV     ES,[DMAADD+2]
  1972.         XCHG    AX,BX           ;Save the record count temporarily
  1973.         XOR     AX,AX           ;Fill with zeros
  1974.         SHR     CX,1
  1975.         JNC     EVENFIL
  1976.         STOSB
  1977. EVENFIL:
  1978.         REP     STOSW
  1979.         XCHG    AX,BX           ;Restore record count to AX
  1980.         POP     ES
  1981.         INC     AX              ;Add last (partial) record to total
  1982. FULLREC:
  1983.         MOV     CX,AX
  1984.         MOV     DI,SI           ;ES:DI point to FCB
  1985. SETCLUS:
  1986.         MOV     AX,[CLUSNUM]
  1987.         MOV     ES:[DI.LSTCLUS],AX
  1988.         MOV     AX,[LASTPOS]
  1989.         MOV     ES:[DI.CLUSPOS],AX
  1990. ADDREC:
  1991.         MOV     AX,WORD PTR [RECPOS]
  1992.         MOV     DX,WORD PTR [RECPOS+2]
  1993.         JCXZ    RET28           ;If no records read, don't change position
  1994.         DEC     CX
  1995.         ADD     AX,CX           ;Update current record position
  1996.         ADC     DX,0
  1997.         INC     CX      
  1998. RET28:  RET
  1999.  
  2000. RDLAST:
  2001.         MOV     AX,[BYTCNT2]
  2002.         OR      AX,AX
  2003.         JZ      SETFCB
  2004.         MOV     [BYTCNT1],AX
  2005.         CALL    NEXTSEC
  2006.         JC      SETFCB
  2007.         MOV     [BYTSECPOS],0
  2008.         CALL    BUFRD
  2009.         JMP     SHORT SETFCB
  2010.  
  2011. WRTDEV:
  2012.         PUSH    DS
  2013.         LDS     SI,DWORD PTR [DMAADD]
  2014.         OR      BL,40H
  2015.         INC     BL
  2016.         JZ      WRTCON
  2017.         INC     BL
  2018.         JZ      WRTAUX
  2019.         INC     BL
  2020.         JZ      ENDWRDEV        ;Done if device is NUL
  2021. WRTLST:
  2022.         LODSB
  2023.         CMP     AL,1AH
  2024.         JZ      ENDWRDEV
  2025.         CALL    LISTOUT
  2026.         LOOP    WRTLST
  2027.         JMP     SHORT ENDWRDEV
  2028.  
  2029. WRTAUX:
  2030.         LODSB
  2031.         CALL    AUXOUT
  2032.         CMP     AL,1AH
  2033.         LOOPNZ  WRTAUX
  2034.         JMP     SHORT ENDWRDEV
  2035.  
  2036. WRTCON:
  2037.         LODSB
  2038.         CMP     AL,1AH
  2039.         JZ      ENDWRDEV
  2040.         CALL    OUT
  2041.         LOOP    WRTCON
  2042. ENDWRDEV:
  2043.         POP     DS
  2044.         MOV     CX,[RECCNT]
  2045.         MOV     DI,[FCB]
  2046.         JMP     SHORT ADDREC
  2047.  
  2048. HAVSTART:
  2049.         MOV     CX,AX
  2050.         CALL    SKPCLP
  2051.         JCXZ    DOWRTJ
  2052.         CALL    ALLOCATE
  2053.         JNC     DOWRTJ
  2054. WRTERR:
  2055.         MOV     BYTE PTR [DSKERR],1
  2056. LVDSK:
  2057.         MOV     AX,WORD PTR [RECPOS]
  2058.         MOV     DX,WORD PTR [RECPOS+2]
  2059.         MOV     DI,[FCB]
  2060.         RET
  2061.  
  2062. DOWRTJ: JMP     DOWRT
  2063.  
  2064. WRTEOFJ:
  2065.         JMP     WRTEOF
  2066.  
  2067. STORE:
  2068.  
  2069. ; Inputs:
  2070. ;       DS:DI point to FCB
  2071. ;       DX:AX = Position in file of disk transfer
  2072. ;       CX = Record count
  2073. ; Outputs:
  2074. ;       DX:AX = Position of last record written
  2075. ;       CX = No. of records written
  2076. ;       ES:DI point to FCB
  2077. ;       LSTCLUS, CLUSPOS fields in FCB set
  2078.  
  2079.         CALL    SETUP
  2080.         CALL    DATE16
  2081.         MOV     ES:[DI.FDATE],AX
  2082.         MOV     ES:[DI.FTIME],DX
  2083.         OR      BL,BL
  2084.         JS      WRTDEV
  2085.         AND     BL,3FH          ;Mark file as dirty
  2086.         MOV     ES:[DI.DEVID],BL
  2087.         CALL    BREAKDOWN
  2088.         MOV     AX,WORD PTR [BYTPOS]
  2089.         MOV     DX,WORD PTR [BYTPOS+2]
  2090.         JCXZ    WRTEOFJ
  2091.         DEC     CX
  2092.         ADD     AX,CX
  2093.         ADC     DX,0            ;AX:DX=last byte accessed
  2094.         DIV     [BP.SECSIZ]     ;AX=last sector accessed
  2095.         MOV     CL,[BP.CLUSSHFT]
  2096.         SHR     AX,CL           ;Last cluster to be accessed
  2097.         PUSH    AX
  2098.         MOV     AX,ES:WORD PTR [DI.FILSIZ]
  2099.         MOV     DX,ES:WORD PTR [DI.FILSIZ+2]
  2100.         DIV     [BP.SECSIZ]
  2101.         OR      DX,DX
  2102.         JZ      NORNDUP
  2103.         INC     AX              ;Round up if any remainder
  2104. NORNDUP:
  2105.         MOV     [VALSEC],AX     ;Number of sectors that have been written
  2106.         POP     AX
  2107.         MOV     CX,[CLUSNUM]    ;First cluster accessed
  2108.         CALL    FNDCLUS
  2109.         MOV     [CLUSNUM],BX
  2110.         MOV     [LASTPOS],DX
  2111.         SUB     AX,DX           ;Last cluster minus current cluster
  2112.         JZ      DOWRT           ;If we have last clus, we must have first
  2113.         JCXZ    HAVSTART        ;See if no more data
  2114.         PUSH    CX              ;No. of clusters short of first
  2115.         MOV     CX,AX
  2116.         CALL    ALLOCATE
  2117.         POP     AX
  2118.         JC      WRTERR
  2119.         MOV     CX,AX
  2120.         MOV     DX,[LASTPOS]
  2121.         INC     DX
  2122.         DEC     CX
  2123.         JZ      NOSKIP
  2124.         CALL    SKPCLP
  2125. NOSKIP:
  2126.         MOV     [CLUSNUM],BX
  2127.         MOV     [LASTPOS],DX
  2128. DOWRT:
  2129.         CMP     [BYTCNT1],0
  2130.         JZ      WRTMID
  2131.         MOV     BX,[CLUSNUM]
  2132.         CALL    BUFWRT  
  2133. WRTMID:
  2134.         MOV     AX,[SECCNT]
  2135.         OR      AX,AX
  2136.         JZ      WRTLAST
  2137.         ADD     [SECPOS],AX
  2138.         CALL    NEXTSEC
  2139.         MOV     BYTE PTR [TRANS],1      ;A transfer is taking place
  2140.         MOV     DL,[SECCLUSPOS]
  2141.         MOV     BX,[CLUSNUM]
  2142.         MOV     CX,[SECCNT]
  2143. WRTLP:
  2144.         CALL    OPTIMIZE
  2145.         JC      NOTINBUF        ;Is one of the sectors buffered?
  2146.         MOV     [BUFSECNO],0    ;If so, invalidate the buffer since we're
  2147.         MOV     WORD PTR [BUFDRVNO],0FFH        ;       completely rewritting it
  2148. NOTINBUF:
  2149.         PUSH    DI
  2150.         PUSH    AX
  2151.         PUSH    DS
  2152.         MOV     DS,[DMAADD+2]
  2153.         CALL    DWRITE
  2154.         POP     DS
  2155.         POP     CX
  2156.         POP     BX
  2157.         JCXZ    WRTLAST
  2158.         MOV     DL,0
  2159.         INC     [LASTPOS]       ;We'll be using next cluster
  2160.         JMP     SHORT WRTLP
  2161. WRTLAST:
  2162.         MOV     AX,[BYTCNT2]
  2163.         OR      AX,AX
  2164.         JZ      FINWRT
  2165.         MOV     [BYTCNT1],AX
  2166.         CALL    NEXTSEC
  2167.         MOV     [BYTSECPOS],0
  2168.         CALL    BUFWRT
  2169. FINWRT:
  2170.         MOV     AX,[NEXTADD]
  2171.         SUB     AX,[DMAADD]
  2172.         ADD     AX,WORD PTR [BYTPOS]
  2173.         MOV     DX,WORD PTR [BYTPOS+2]
  2174.         ADC     DX,0
  2175.         MOV     CX,DX
  2176.         MOV     DI,[FCB]
  2177.         CMP     AX,ES:WORD PTR [DI.FILSIZ]
  2178.         SBB     CX,ES:WORD PTR [DI.FILSIZ+2]
  2179.         JB      SAMSIZ
  2180.         MOV     ES:WORD PTR [DI.FILSIZ],AX
  2181.         MOV     ES:WORD PTR [DI.FILSIZ+2],DX
  2182. SAMSIZ:
  2183.         MOV     CX,[RECCNT]
  2184.         JMP     SETCLUS
  2185.  
  2186.  
  2187. WRTERRJ:JMP     WRTERR
  2188.  
  2189. WRTEOF:
  2190.         MOV     CX,AX
  2191.         OR      CX,DX
  2192.         JZ      KILLFIL
  2193.         SUB     AX,1
  2194.         SBB     DX,0
  2195.         DIV     [BP.SECSIZ]
  2196.         MOV     CL,[BP.CLUSSHFT]
  2197.         SHR     AX,CL
  2198.         MOV     CX,AX
  2199.         CALL    FNDCLUS
  2200.         JCXZ    RELFILE
  2201.         CALL    ALLOCATE
  2202.         JC      WRTERRJ
  2203. UPDATE:
  2204.         MOV     DI,[FCB]
  2205.         MOV     AX,WORD PTR [BYTPOS]
  2206.         MOV     ES:WORD PTR [DI.FILSIZ],AX
  2207.         MOV     AX,WORD PTR [BYTPOS+2]
  2208.         MOV     ES:WORD PTR [DI.FILSIZ+2],AX
  2209.         XOR     CX,CX
  2210.         JMP     ADDREC
  2211.  
  2212. RELFILE:
  2213.         MOV     DX,0FFFH
  2214.         CALL    RELBLKS
  2215. SETDIRT:
  2216.         MOV     BYTE PTR [SI-1],1
  2217.         JMP     SHORT UPDATE
  2218.  
  2219. KILLFIL:
  2220.         XOR     BX,BX
  2221.         XCHG    BX,ES:[DI.FIRCLUS]
  2222.         OR      BX,BX
  2223.         JZ      UPDATE
  2224.         CALL    RELEASE
  2225.         JMP     SHORT SETDIRT
  2226.  
  2227.  
  2228. OPTIMIZE:
  2229.  
  2230. ; Inputs:
  2231. ;       DS = CS
  2232. ;       BX = Physical cluster
  2233. ;       CX = No. of records
  2234. ;       DL = sector within cluster
  2235. ;       BP = Base of drives parameters
  2236. ;       [NEXTADD] = transfer address
  2237. ; Outputs:
  2238. ;       AX = No. of records remaining
  2239. ;       BX = Transfer address
  2240. ;       CX = No. or records to be transferred
  2241. ;       DX = Physical sector address
  2242. ;       DI = Next cluster
  2243. ;       Carry clear if a sector to transfer is in the buffer
  2244. ;       Carry set otherwise
  2245. ;       [CLUSNUM] = Last cluster accessed
  2246. ;       [NEXTADD] updated
  2247. ; BP unchanged. Note that segment of transfer not set.
  2248.  
  2249.         PUSH    DX
  2250.         PUSH    BX
  2251.         MOV     AL,[BP.CLUSMSK]
  2252.         INC     AL              ;Number of sectors per cluster
  2253.         MOV     AH,AL
  2254.         SUB     AL,DL           ;AL = Number of sectors left in first cluster
  2255.         MOV     DX,CX
  2256.         MOV     SI,[BP.FAT]
  2257.         MOV     CX,0
  2258. OPTCLUS:
  2259. ;AL has number of sectors available in current cluster
  2260. ;AH has number of sectors available in next cluster
  2261. ;BX has current physical cluster
  2262. ;CX has number of sequential sectors found so far
  2263. ;DX has number of sectors left to transfer
  2264. ;SI has FAT pointer
  2265.         CALL    UNPACK
  2266.         ADD     CL,AL
  2267.         ADC     CH,0
  2268.         CMP     CX,DX
  2269.         JAE     BLKDON
  2270.         MOV     AL,AH
  2271.         INC     BX
  2272.         CMP     DI,BX
  2273.         JZ      OPTCLUS
  2274.         DEC     BX
  2275. FINCLUS:
  2276.         MOV     [CLUSNUM],BX    ;Last cluster accessed
  2277.         SUB     DX,CX           ;Number of sectors still needed
  2278.         PUSH    DX
  2279.         MOV     AX,CX
  2280.         MUL     [BP.SECSIZ]     ;Number of sectors times sector size
  2281.         MOV     SI,[NEXTADD]
  2282.         ADD     AX,SI           ;Adjust by size of transfer
  2283.         MOV     [NEXTADD],AX
  2284.         POP     AX              ;Number of sectors still needed
  2285.         POP     DX              ;Starting cluster
  2286.         SUB     BX,DX           ;Number of new clusters accessed
  2287.         ADD     [LASTPOS],BX
  2288.         POP     BX              ;BL = sector postion within cluster
  2289.         CALL    FIGREC
  2290.         MOV     BX,SI
  2291. ;Now let's see if any of these sectors are already in the buffer
  2292.         CMP     [BUFSECNO],DX
  2293.         JC      RET100          ;If DX > [BUFSECNO] then not in buffer
  2294.         MOV     SI,DX
  2295.         ADD     SI,CX           ;Last sector + 1
  2296.         CMP     [BUFSECNO],SI
  2297.         CMC
  2298.         JC      RET100          ;If SI <= [BUFSECNO] then not in buffer
  2299.         PUSH    AX
  2300.         MOV     AL,[BP.DEVNUM]
  2301.         CMP     AL,[BUFDRVNO]   ;Is buffer for this drive?
  2302.         POP     AX
  2303.         JZ      RET100          ;If so, then we match
  2304.         STC                     ;No match
  2305. RET100: RET
  2306. BLKDON:
  2307.         SUB     CX,DX           ;Number of sectors in cluster we don't want
  2308.         SUB     AH,CL           ;Number of sectors in cluster we accepted
  2309.         DEC     AH              ;Adjust to mean position within cluster
  2310.         MOV     [SECCLUSPOS],AH
  2311.         MOV     CX,DX           ;Anyway, make the total equal to the request
  2312.         JMP     SHORT FINCLUS
  2313.  
  2314.  
  2315. FIGREC:
  2316.  
  2317. ;Inputs:
  2318. ;       DX = Physical cluster number
  2319. ;       BL = Sector postion within cluster
  2320. ;       BP = Base of drive parameters
  2321. ;Outputs:
  2322. ;       DX = physical sector number
  2323. ;No other registers affected.
  2324.  
  2325.         PUSH    CX
  2326.         MOV     CL,[BP.CLUSSHFT]
  2327.         DEC     DX
  2328.         DEC     DX
  2329.         SHL     DX,CL
  2330.         OR      DL,BL
  2331.         ADD     DX,[BP.FIRREC]
  2332.         POP     CX
  2333.         RET
  2334.  
  2335. GETREC:
  2336.  
  2337. ; Inputs:
  2338. ;       DS:DX point to FCB
  2339. ; Outputs:
  2340. ;       CX = 1
  2341. ;       DX:AX = Record number determined by EXTENT and NR fields
  2342. ;       DS:DI point to FCB
  2343. ; No other registers affected.
  2344.  
  2345.         MOV     DI,DX
  2346.         CMP     BYTE PTR [DI],-1        ;Check for extended FCB
  2347.         JNZ     NORMFCB2
  2348.         ADD     DI,7
  2349. NORMFCB2:
  2350.         MOV     CX,1
  2351.         MOV     AL,[DI.NR]
  2352.         MOV     DX,[DI.EXTENT]
  2353.         SHL     AL,1
  2354.         SHR     DX,1
  2355.         RCR     AL,1
  2356.         MOV     AH,DL
  2357.         MOV     DL,DH
  2358.         MOV     DH,0
  2359.         RET
  2360.  
  2361.  
  2362. ALLOCATE:
  2363.  
  2364. ; Inputs:
  2365. ;       DS = CS
  2366. ;       ES = Segment of FCB
  2367. ;       BX = Last cluster of file (0 if null file)
  2368. ;       CX = No. of clusters to allocate
  2369. ;       DX = Position of cluster BX
  2370. ;       BP = Base of drive parameters
  2371. ;       SI = FAT pointer
  2372. ;       [FCB] = Displacement of FCB within segment
  2373. ; Outputs:
  2374. ;       IF insufficient space
  2375. ;         THEN
  2376. ;       Carry set
  2377. ;       CX = max. no. of records that could be added to file
  2378. ;         ELSE
  2379. ;       Carry clear
  2380. ;       BX = First cluster allocated
  2381. ;       FAT is fully updated including dirty bit
  2382. ;       FIRCLUS field of FCB set if file was null
  2383. ; SI,BP unchanged. All other registers destroyed.
  2384.  
  2385.         PUSH    [SI]
  2386.         PUSH    DX
  2387.         PUSH    CX
  2388.         PUSH    BX
  2389.         MOV     AX,BX
  2390. ALLOC:
  2391.         MOV     DX,BX
  2392. FINDFRE:
  2393.         INC     BX
  2394.         CMP     BX,[BP.MAXCLUS]
  2395.         JLE     TRYOUT
  2396.         CMP     AX,1
  2397.         JG      TRYIN
  2398.         POP     BX
  2399.         MOV     DX,0FFFH
  2400.         CALL    RELBLKS
  2401.         POP     AX              ;No. of clusters requested
  2402.         SUB     AX,CX           ;AX=No. of clusters allocated
  2403.         POP     DX
  2404.         POP     [SI]
  2405.         INC     DX              ;Position of first cluster allocated
  2406.         ADD     AX,DX           ;AX=max no. of cluster in file
  2407.         MOV     DL,[BP.CLUSMSK]
  2408.         MOV     DH,0
  2409.         INC     DX              ;DX=records/cluster
  2410.         MUL     DX              ;AX=max no. of records in file
  2411.         MOV     CX,AX
  2412.         SUB     CX,WORD PTR [RECPOS]    ;CX=max no. of records that could be written
  2413.         JA      MAXREC
  2414.         XOR     CX,CX           ;If CX was negative, zero it
  2415. MAXREC:
  2416.         STC
  2417. RET11:  RET
  2418.  
  2419. TRYOUT:
  2420.         CALL    UNPACK
  2421.         JZ      HAVFRE
  2422. TRYIN:
  2423.         DEC     AX
  2424.         JLE     FINDFRE
  2425.         XCHG    AX,BX
  2426.         CALL    UNPACK
  2427.         JZ      HAVFRE
  2428.         XCHG    AX,BX
  2429.         JMP     SHORT FINDFRE
  2430. HAVFRE:
  2431.         XCHG    BX,DX
  2432.         MOV     AX,DX
  2433.         CALL    PACK
  2434.         MOV     BX,AX
  2435.         LOOP    ALLOC
  2436.         MOV     DX,0FFFH
  2437.         CALL    PACK
  2438.         MOV     BYTE PTR [SI-1],1
  2439.         POP     BX
  2440.         POP     CX              ;Don't need this stuff since we're successful
  2441.         POP     DX
  2442.         CALL    UNPACK
  2443.         POP     [SI]
  2444.         XCHG    BX,DI
  2445.         OR      DI,DI
  2446.         JNZ     RET11
  2447.         MOV     DI,[FCB]
  2448.         MOV     ES:[DI.FIRCLUS],BX
  2449. RET12:  RET
  2450.  
  2451.  
  2452. RELEASE:
  2453.  
  2454. ; Inputs:
  2455. ;       DS = CS
  2456. ;       BX = Cluster in file
  2457. ;       SI = FAT pointer
  2458. ;       BP = Base of drive parameters
  2459. ; Function:
  2460. ;       Frees cluster chain starting with [BX]
  2461. ; AX,BX,DX,DI all destroyed. Other registers unchanged.
  2462.  
  2463.         XOR     DX,DX
  2464. RELBLKS:
  2465. ; Enter here with DX=0FFFH to put an end-of-file mark
  2466. ; in the first cluster and free the rest in the chain.
  2467.         CALL    UNPACK
  2468.         JZ      RET12
  2469.         MOV     AX,DI
  2470.         CALL    PACK
  2471.         CMP     AX,0FF8H
  2472.         MOV     BX,AX
  2473.         JB      RELEASE
  2474. RET13:  RET
  2475.  
  2476.  
  2477. GETEOF:
  2478.  
  2479. ; Inputs:
  2480. ;       BX = Cluster in a file
  2481. ;       SI = Base of drive FAT
  2482. ;       DS = CS
  2483. ; Outputs:
  2484. ;       BX = Last cluster in the file
  2485. ; DI destroyed. No other registers affected.
  2486.  
  2487.         CALL    UNPACK
  2488.         CMP     DI,0FF8H
  2489.         JAE     RET13
  2490.         MOV     BX,DI
  2491.         JMP     SHORT GETEOF
  2492.  
  2493.  
  2494. SRCHFRST: ;System call 17
  2495.         CALL    GETFILE
  2496. SAVPLCE:
  2497. ; Search-for-next enters here to save place and report
  2498. ; findings.
  2499.         JC      KILLSRCH
  2500.         OR      BH,BH
  2501.         JS      SRCHDEV
  2502.         MOV     AX,[LASTENT]
  2503.         MOV     ES:[DI.FILDIRENT],AX
  2504.         MOV     ES:[DI.DRVBP],BP
  2505. ;Information in directory entry must be copied into the first
  2506. ; 33 bytes starting at the disk transfer address.
  2507.         MOV     SI,BX
  2508.         LES     DI,DWORD PTR [DMAADD]
  2509.         MOV     AX,00FFH
  2510.         CMP     AL,[EXTFCB]
  2511.         JNZ     NORMFCB
  2512.         STOSW
  2513.         INC     AL
  2514.         STOSW
  2515.         STOSW
  2516.         MOV     AL,[ATTRIB]
  2517.         STOSB
  2518. NORMFCB:
  2519.         MOV     AL,[THISDRV]
  2520.         INC     AL
  2521.         STOSB   ;Set drive number
  2522.         MOV     CX,16
  2523.         REP     MOVSW   ;Copy remaining 10 characters of name
  2524.         XOR     AL,AL
  2525.         RET
  2526.  
  2527. KILLSRCH:
  2528. KILLSRCH1       EQU     KILLSRCH+1
  2529. ;The purpose of the KILLSRCH1 label is to provide a jump label to the following
  2530. ;   instruction which leaves out the segment override.
  2531.         MOV     WORD PTR ES:[DI.FILDIRENT],-1
  2532.         MOV     AL,-1
  2533.         RET
  2534.  
  2535. SRCHDEV:
  2536.         MOV     ES:[DI.FILDIRENT],BX
  2537.         LES     DI,DWORD PTR [DMAADD]
  2538.         XOR     AX,AX
  2539.         STOSB           ;Zero drive byte
  2540.         SUB     SI,4            ;Point to device name
  2541.         MOVSW
  2542.         MOVSW
  2543.         MOV     AX,2020H
  2544.         STOSB
  2545.         STOSW
  2546.         STOSW
  2547.         STOSW                   ;Fill with 8 blanks
  2548.         XOR     AX,AX
  2549.         MOV     CX,10
  2550.         REP     STOSW
  2551.         STOSB
  2552. RET14:  RET
  2553.  
  2554. SRCHNXT: ;System call 18
  2555.         CALL    MOVNAME
  2556.         MOV     DI,DX
  2557.         JC      NEAR PTR KILLSRCH1
  2558.         MOV     BP,[DI.DRVBP]
  2559.         MOV     AX,[DI.FILDIRENT]
  2560.         OR      AX,AX
  2561.         JS      NEAR PTR KILLSRCH1
  2562.         PUSH    DX
  2563.         PUSH    DS
  2564.         PUSH    CS
  2565.         POP     DS
  2566.         MOV     [LASTENT],AX
  2567.         CALL    CONTSRCH
  2568.         POP     ES
  2569.         POP     DI
  2570.         JMP     SAVPLCE
  2571.  
  2572.  
  2573. FILESIZE: ;System call 35
  2574.         CALL    GETFILE
  2575.         MOV     AL,-1
  2576.         JC      RET14
  2577.         ADD     DI,33           ;Write size in RR field
  2578.         MOV     CX,ES:[DI.RECSIZ-33]
  2579.         OR      CX,CX
  2580.         JNZ     RECOK
  2581.         MOV     CX,128
  2582. RECOK:
  2583.         XOR     AX,AX
  2584.         XOR     DX,DX           ;Intialize size to zero
  2585.         OR      BH,BH           ;Check for named I/O device
  2586.         JS      DEVSIZ
  2587.         INC     SI
  2588.         INC     SI              ;Point to length field
  2589.         MOV     AX,[SI+2]       ;Get high word of size
  2590.         DIV     CX
  2591.         PUSH    AX              ;Save high part of result
  2592.         LODSW           ;Get low word of size
  2593.         DIV     CX
  2594.         OR      DX,DX           ;Check for zero remainder
  2595.         POP     DX
  2596.         JZ      DEVSIZ
  2597.         INC     AX              ;Round up for partial record
  2598.         JNZ     DEVSIZ          ;Propagate carry?
  2599.         INC     DX
  2600. DEVSIZ:
  2601.         STOSW
  2602.         MOV     AX,DX
  2603.         STOSB
  2604.         MOV     AL,0
  2605.         CMP     CX,64
  2606.         JAE     RET14           ;Only 3-byte field if RECSIZ >= 64
  2607.         MOV     ES:[DI],AH
  2608.         RET
  2609.  
  2610.  
  2611. SETDMA: ;System call 26
  2612.         MOV     CS:[DMAADD],DX
  2613.         MOV     CS:[DMAADD+2],DS
  2614.         RET
  2615.  
  2616. NOSUCHDRV:
  2617.         MOV     AL,-1
  2618.         RET
  2619.  
  2620. GETFATPT: ;System call 27
  2621.         MOV     DL,0                    ;Use default drive
  2622.  
  2623. GETFATPTDL:     ;System call 28
  2624.         PUSH    CS
  2625.         POP     DS
  2626.         MOV     AL,DL
  2627.         CALL    GETTHISDRV
  2628.         JC      NOSUCHDRV
  2629.         CALL    FATREAD
  2630.         MOV     BX,[BP.FAT]
  2631.         MOV     AL,[BP.CLUSMSK]
  2632.         INC     AL
  2633.         MOV     DX,[BP.MAXCLUS]
  2634.         DEC     DX
  2635.         MOV     CX,[BP.SECSIZ]
  2636.         LDS     SI,DWORD PTR [SPSAVE]
  2637.         MOV     [SI.BXSAVE],BX
  2638.         MOV     [SI.DXSAVE],DX
  2639.         MOV     [SI.CXSAVE],CX
  2640.         MOV     [SI.DSSAVE],CS
  2641.         RET
  2642.  
  2643.  
  2644. GETDSKPT: ;System call 31
  2645.         PUSH    CS
  2646.         POP     DS
  2647.         MOV     AL,[CURDRV]
  2648.         MOV     [THISDRV],AL
  2649.         CALL    FATREAD
  2650.         LDS     SI,DWORD PTR [SPSAVE]
  2651.         MOV     [SI.BXSAVE],BP
  2652.         MOV     [SI.DSSAVE],CS
  2653.         RET
  2654.  
  2655.  
  2656. DSKRESET: ;System call 13
  2657.         PUSH    CS
  2658.         POP     DS
  2659. WRTFATS:
  2660. ; DS=CS. Writes back all dirty FATs. All registers destroyed.
  2661.         XOR     AL,AL
  2662.         XCHG    AL,[DIRTYBUF]
  2663.         OR      AL,AL
  2664.         JZ      NOBUF
  2665.         MOV     BP,[BUFDRVBP]
  2666.         MOV     DX,[BUFSECNO]
  2667.         MOV     BX,[BUFFER]
  2668.         MOV     CX,1
  2669.         CALL    DWRITE
  2670. NOBUF:
  2671.         MOV     CL,[NUMIO]
  2672.         MOV     CH,0
  2673.         MOV     BP,[DRVTAB]
  2674. WRTFAT:
  2675.         PUSH    CX
  2676.         CALL    CHKFATWRT
  2677.         POP     CX
  2678.         ADD     BP,DPBSIZ
  2679.         LOOP    WRTFAT
  2680.         RET
  2681.  
  2682.  
  2683. GETDRV: ;System call 25
  2684.         MOV     AL,CS:[CURDRV]
  2685. RET15:  RET
  2686.  
  2687.  
  2688. SETRNDREC: ;System call 36
  2689.         CALL    GETREC
  2690.         MOV     [DI+33],AX
  2691.         MOV     [DI+35],DL
  2692.         CMP     [DI.RECSIZ],64
  2693.         JAE     RET15
  2694.         MOV     [DI+36],DH      ;Set 4th byte only if record size < 64
  2695. RET16:  RET
  2696.  
  2697.  
  2698. SELDSK: ;System call 14
  2699.         MOV     AL,CS:[NUMDRV]
  2700.         CMP     DL,AL
  2701.         JNB     RET17
  2702.         MOV     CS:[CURDRV],DL
  2703. RET17:  RET
  2704.  
  2705. BUFIN:  ;System call 10
  2706.         MOV     AX,CS
  2707.         MOV     ES,AX
  2708.         MOV     SI,DX
  2709.         MOV     CH,0
  2710.         LODSW
  2711.         OR      AL,AL
  2712.         JZ      RET17
  2713.         MOV     BL,AH
  2714.         MOV     BH,CH
  2715.         CMP     AL,BL
  2716.         JBE     NOEDIT
  2717.         CMP     BYTE PTR [BX+SI],0DH
  2718.         JZ      EDITON
  2719. NOEDIT:
  2720.         MOV     BL,CH
  2721. EDITON:
  2722.         MOV     DL,AL
  2723.         DEC     DX
  2724. NEWLIN:
  2725.         MOV     AL,CS:[CARPOS]
  2726.         MOV     CS:[STARTPOS],AL
  2727.         PUSH    SI
  2728.         MOV     DI,OFFSET DOSGROUP:INBUF
  2729.         MOV     AH,CH
  2730.         MOV     BH,CH
  2731.         MOV     DH,CH
  2732. GETCH:
  2733.         CALL    IN
  2734.         CMP     AL,"F"-"@"      ;Ignore ^F
  2735.         JZ      GETCH
  2736.         CMP     AL,CS:ESCCHAR
  2737.         JZ      ESC
  2738.         CMP     AL,7FH
  2739.         JZ      BACKSP
  2740.         CMP     AL,8
  2741.         JZ      BACKSP
  2742.         CMP     AL,13
  2743.         JZ      ENDLIN
  2744.         CMP     AL,10
  2745.         JZ      PHYCRLF
  2746.         CMP     AL,CANCEL
  2747.         JZ      KILNEW
  2748. SAVCH:
  2749.         CMP     DH,DL
  2750.         JAE     BUFFUL
  2751.         STOSB
  2752.         INC     DH
  2753.         CALL    BUFOUT
  2754.         OR      AH,AH
  2755.         JNZ     GETCH
  2756.         CMP     BH,BL
  2757.         JAE     GETCH
  2758.         INC     SI
  2759.         INC     BH
  2760.         JMP     SHORT GETCH
  2761.  
  2762. BUFFUL:
  2763.         MOV     AL,7
  2764.         CALL    OUT
  2765.         JMP     SHORT GETCH
  2766.  
  2767. ESC:
  2768.         CALL    IN
  2769.         MOV     CL,ESCTABLEN
  2770.         PUSH    DI
  2771.         MOV     DI,OFFSET DOSGROUP:ESCTAB
  2772.         REPNE   SCASB
  2773.         POP     DI
  2774.         SHL     CX,1
  2775.         MOV     BP,CX
  2776.         JMP     [BP+OFFSET DOSGROUP:ESCFUNC]
  2777.  
  2778. ENDLIN:
  2779.         STOSB
  2780.         CALL    OUT
  2781.         POP     DI
  2782.         MOV     [DI-1],DH
  2783.         INC     DH
  2784. COPYNEW:
  2785.         MOV     BP,ES
  2786.         MOV     BX,DS
  2787.         MOV     ES,BX
  2788.         MOV     DS,BP
  2789.         MOV     SI,OFFSET DOSGROUP:INBUF
  2790.         MOV     CL,DH
  2791.         REP     MOVSB
  2792.         RET
  2793. CRLF:
  2794.         MOV     AL,13
  2795.         CALL    OUT
  2796.         MOV     AL,10
  2797.         JMP     OUT
  2798.  
  2799. PHYCRLF:
  2800.         CALL    CRLF
  2801.         JMP     SHORT GETCH
  2802.  
  2803. KILNEW:
  2804.         MOV     AL,"\"
  2805.         CALL    OUT
  2806.         POP     SI
  2807. PUTNEW:
  2808.         CALL    CRLF
  2809.         MOV     AL,CS:[STARTPOS]
  2810.         CALL    TAB
  2811.         JMP     NEWLIN
  2812.  
  2813. BACKSP:
  2814.         OR      DH,DH
  2815.         JZ      OLDBAK
  2816.         CALL    BACKUP
  2817.         MOV     AL,ES:[DI]
  2818.         CMP     AL," "
  2819.         JAE     OLDBAK
  2820.         CMP     AL,9
  2821.         JZ      BAKTAB
  2822.         CALL    BACKMES
  2823. OLDBAK:
  2824.         OR      AH,AH
  2825.         JNZ     GETCH1
  2826.         OR      BH,BH
  2827.         JZ      GETCH1
  2828.         DEC     BH
  2829.         DEC     SI
  2830. GETCH1:
  2831.         JMP     GETCH
  2832. BAKTAB:
  2833.         PUSH    DI
  2834.         DEC     DI
  2835.         STD
  2836.         MOV     CL,DH
  2837.         MOV     AL," "
  2838.         PUSH    BX
  2839.         MOV     BL,7
  2840.         JCXZ    FIGTAB
  2841. FNDPOS:
  2842.         SCASB
  2843.         JNA     CHKCNT
  2844.         CMP     ES:BYTE PTR [DI+1],9
  2845.         JZ      HAVTAB
  2846.         DEC     BL
  2847. CHKCNT:
  2848.         LOOP    FNDPOS
  2849. FIGTAB:
  2850.         SUB     BL,CS:[STARTPOS]
  2851. HAVTAB:
  2852.         SUB     BL,DH
  2853.         ADD     CL,BL
  2854.         AND     CL,7
  2855.         CLD
  2856.         POP     BX
  2857.         POP     DI
  2858.         JZ      OLDBAK
  2859. TABBAK:
  2860.         CALL    BACKMES
  2861.         LOOP    TABBAK
  2862.         JMP     SHORT OLDBAK
  2863. BACKUP:
  2864.         DEC     DH
  2865.         DEC     DI
  2866. BACKMES:
  2867.         MOV     AL,8
  2868.         CALL    OUT
  2869.         MOV     AL," "
  2870.         CALL    OUT
  2871.         MOV     AL,8
  2872.         JMP     OUT
  2873.  
  2874. TWOESC:
  2875.         MOV     AL,ESCCH
  2876.         JMP     SAVCH
  2877.  
  2878. COPYLIN:
  2879.         MOV     CL,BL
  2880.         SUB     CL,BH
  2881.         JMP     SHORT COPYEACH
  2882.  
  2883. COPYSTR:
  2884.         CALL    FINDOLD
  2885.         JMP     SHORT COPYEACH
  2886.  
  2887. COPYONE:
  2888.         MOV     CL,1
  2889. COPYEACH:
  2890.         MOV     AH,0
  2891.         CMP     DH,DL
  2892.         JZ      GETCH2
  2893.         CMP     BH,BL
  2894.         JZ      GETCH2
  2895.         LODSB
  2896.         STOSB
  2897.         CALL    BUFOUT
  2898.         INC     BH
  2899.         INC     DH
  2900.         LOOP    COPYEACH
  2901. GETCH2:
  2902.         JMP     GETCH
  2903.  
  2904. SKIPONE:
  2905.         CMP     BH,BL
  2906.         JZ      GETCH2
  2907.         INC     BH
  2908.         INC     SI
  2909.         JMP     GETCH
  2910.  
  2911. SKIPSTR:
  2912.         CALL    FINDOLD
  2913.         ADD     SI,CX
  2914.         ADD     BH,CL
  2915.         JMP     GETCH
  2916.  
  2917. FINDOLD:
  2918.         CALL    IN
  2919.         MOV     CL,BL
  2920.         SUB     CL,BH
  2921.         JZ      NOTFND
  2922.         DEC     CX
  2923.         JZ      NOTFND
  2924.         PUSH    ES
  2925.         PUSH    DS
  2926.         POP     ES
  2927.         PUSH    DI
  2928.         MOV     DI,SI
  2929.         INC     DI
  2930.         REPNE   SCASB
  2931.         POP     DI
  2932.         POP     ES
  2933.         JNZ     NOTFND
  2934.         NOT     CL
  2935.         ADD     CL,BL
  2936.         SUB     CL,BH
  2937. RET30:  RET
  2938. NOTFND:
  2939.         POP     BP
  2940.         JMP     GETCH
  2941.  
  2942. REEDIT:
  2943.         MOV     AL,"@"
  2944.         CALL    OUT
  2945.         POP     DI
  2946.         PUSH    DI
  2947.         PUSH    ES
  2948.         PUSH    DS
  2949.         CALL    COPYNEW
  2950.         POP     DS
  2951.         POP     ES
  2952.         POP     SI
  2953.         MOV     BL,DH
  2954.         JMP     PUTNEW
  2955.  
  2956. ENTERINS:
  2957.         IF      TOGLINS
  2958.         NOT     AH
  2959.         JMP     GETCH
  2960.         ENDIF
  2961.         IF      NOT TOGLINS
  2962.         MOV     AH,-1
  2963.         JMP     GETCH
  2964.  
  2965. EXITINS:
  2966.         MOV     AH,0
  2967.         JMP     GETCH
  2968.         ENDIF
  2969.  
  2970. ESCFUNC DW      GETCH
  2971.         DW      TWOESC
  2972.         IF      NOT TOGLINS
  2973.         DW      EXITINS
  2974.         ENDIF
  2975.         DW      ENTERINS
  2976.         DW      BACKSP
  2977.         DW      REEDIT
  2978.         DW      KILNEW
  2979.         DW      COPYLIN
  2980.         DW      SKIPSTR
  2981.         DW      COPYSTR
  2982.         DW      SKIPONE
  2983.         DW      COPYONE
  2984.  
  2985.         IF      IBM
  2986.         DW      COPYONE
  2987.         DW      CTRLZ
  2988. CTRLZ:
  2989.         MOV     AL,"Z"-"@"
  2990.         JMP     SAVCH
  2991.         ENDIF
  2992. BUFOUT:
  2993.         CMP     AL," "
  2994.         JAE     OUT
  2995.         CMP     AL,9
  2996.         JZ      OUT
  2997.         PUSH    AX
  2998.         MOV     AL,"^"
  2999.         CALL    OUT
  3000.         POP     AX
  3001.         OR      AL,40H
  3002.         JMP     SHORT OUT
  3003.  
  3004. NOSTOP:
  3005.         CMP     AL,"P"-"@"
  3006.         JZ      INCHK
  3007.         IF      NOT TOGLPRN
  3008.         CMP     AL,"N"-"@"
  3009.         JZ      INCHK
  3010.         ENDIF
  3011.         CMP     AL,"C"-"@"
  3012.         JZ      INCHK
  3013.         RET
  3014.  
  3015. CONOUT: ;System call 2
  3016.         MOV     AL,DL
  3017. OUT:
  3018.         CMP     AL,20H
  3019.         JB      CTRLOUT
  3020.         CMP     AL,7FH
  3021.         JZ      OUTCH
  3022.         INC     CS:BYTE PTR [CARPOS]
  3023. OUTCH:
  3024.         PUSH    AX
  3025.         CALL    STATCHK
  3026.         POP     AX
  3027.         CALL    FAR PTR BIOSOUT
  3028.         TEST    CS:BYTE PTR [PFLAG],-1
  3029.         JZ      RET18
  3030.         CALL    FAR PTR BIOSPRINT
  3031. RET18:  RET
  3032.  
  3033. STATCHK:
  3034.         CALL    FAR PTR BIOSSTAT
  3035.         JZ      RET18
  3036.         CMP     AL,'S'-'@'
  3037.         JNZ     NOSTOP
  3038.         CALL    FAR PTR BIOSIN          ;Eat Cntrl-S
  3039. INCHK:
  3040.         CALL    FAR PTR BIOSIN
  3041.         CMP     AL,'P'-'@'
  3042.         JZ      PRINTON
  3043.         IF      NOT TOGLPRN
  3044.         CMP     AL,'N'-'@'
  3045.         JZ      PRINTOFF
  3046.         ENDIF
  3047.         CMP     AL,'C'-'@'
  3048.         JNZ     RET18
  3049. ; Ctrl-C handler.
  3050. ; "^C" and CR/LF is printed. Then the user registers are restored and the
  3051. ; user CTRL-C handler is executed. At this point the top of the stack has
  3052. ; 1) the interrupt return address should the user CTRL-C handler wish to
  3053. ; allow processing to continue; 2) the original interrupt return address
  3054. ; to the code that performed the function call in the first place. If the
  3055. ; user CTRL-C handler wishes to continue, it must leave all registers
  3056. ; unchanged and IRET. The function that was interrupted will simply be
  3057. ; repeated.
  3058.         MOV     AL,3            ;Display "^C"
  3059.         CALL    BUFOUT
  3060.         CALL    CRLF
  3061.         CLI                     ;Prepare to play with stack
  3062.         MOV     SS,CS:[SSSAVE]
  3063.         MOV     SP,CS:[SPSAVE]  ;User stack now restored
  3064.         POP     AX
  3065.         POP     BX
  3066.         POP     CX
  3067.         POP     DX
  3068.         POP     SI
  3069.         POP     DI
  3070.         POP     BP
  3071.         POP     DS
  3072.         POP     ES              ;User registers now restored
  3073.         INT     CONTC           ;Execute user Ctrl-C handler
  3074.         JMP     COMMAND         ;Repeat command otherwise
  3075.  
  3076. PRINTON:
  3077.         IF      TOGLPRN
  3078.         NOT     CS:BYTE PTR [PFLAG]
  3079.         RET
  3080.         ENDIF
  3081.         IF      NOT TOGLPRN
  3082.         MOV     CS:BYTE PTR [PFLAG],1
  3083.         RET
  3084.  
  3085. PRINTOFF:
  3086.         MOV     CS:BYTE PTR [PFLAG],0
  3087.         RET
  3088.         ENDIF
  3089.  
  3090. CTRLOUT:
  3091.         CMP     AL,13
  3092.         JZ      ZERPOS
  3093.         CMP     AL,8
  3094.         JZ      BACKPOS
  3095.         CMP     AL,9
  3096.         JNZ     OUTCHJ
  3097.         MOV     AL,CS:[CARPOS]
  3098.         OR      AL,0F8H
  3099.         NEG     AL
  3100. TAB:
  3101.         PUSH    CX
  3102.         MOV     CL,AL
  3103.         MOV     CH,0
  3104.         JCXZ    POPTAB
  3105. TABLP:
  3106.         MOV     AL," "
  3107.         CALL    OUT
  3108.         LOOP    TABLP
  3109. POPTAB:
  3110.         POP     CX
  3111. RET19:  RET
  3112.  
  3113. ZERPOS:
  3114.         MOV     CS:BYTE PTR [CARPOS],0
  3115. OUTCHJ: JMP     OUTCH
  3116.  
  3117. BACKPOS:
  3118.         DEC     CS:BYTE PTR [CARPOS]
  3119.         JMP     OUTCH
  3120.  
  3121.  
  3122. CONSTAT: ;System call 11
  3123.         CALL    STATCHK
  3124.         MOV     AL,0
  3125.         JZ      RET19
  3126.         OR      AL,-1
  3127.         RET
  3128.  
  3129.  
  3130. CONIN:  ;System call 1
  3131.         CALL    IN
  3132.         PUSH    AX
  3133.         CALL    OUT
  3134.         POP     AX
  3135.         RET
  3136.  
  3137.  
  3138. IN:     ;System call 8
  3139.         CALL    INCHK
  3140.         JZ      IN
  3141. RET29:  RET
  3142.  
  3143. RAWIO:  ;System call 6
  3144.         MOV     AL,DL
  3145.         CMP     AL,-1
  3146.         JNZ     RAWOUT
  3147.         LDS     SI,DWORD PTR CS:[SPSAVE]                ;Get pointer to register save area
  3148.         CALL    FAR PTR BIOSSTAT
  3149.         JNZ     RESFLG
  3150.         OR      BYTE PTR [SI.FSAVE],40H ;Set user's zero flag
  3151.         XOR     AL,AL
  3152.         RET
  3153.  
  3154. RESFLG:
  3155.         AND     BYTE PTR [SI.FSAVE],0FFH-40H    ;Reset user's zero flag
  3156. RAWINP: ;System call 7
  3157.         CALL    FAR PTR BIOSIN
  3158.         RET
  3159. RAWOUT:
  3160.         CALL    FAR PTR BIOSOUT
  3161.         RET
  3162.  
  3163. LIST:   ;System call 5
  3164.         MOV     AL,DL
  3165. LISTOUT:
  3166.         PUSH    AX
  3167.         CALL    STATCHK
  3168.         POP     AX
  3169.         CALL    FAR PTR BIOSPRINT
  3170. RET20:  RET
  3171.  
  3172. PRTBUF: ;System call 9
  3173.         MOV     SI,DX
  3174. OUTSTR:
  3175.         LODSB
  3176.         CMP     AL,"$"
  3177.         JZ      RET20
  3178.         CALL    OUT
  3179.         JMP     SHORT OUTSTR
  3180.  
  3181. OUTMES: ;String output for internal messages
  3182.         LODS    CS:BYTE PTR [SI]
  3183.         CMP     AL,"$"
  3184.         JZ      RET20
  3185.         CALL    OUT
  3186.         JMP     SHORT OUTMES
  3187.  
  3188.  
  3189. MAKEFCB: ;Interrupt call 41
  3190. DRVBIT  EQU     2
  3191. NAMBIT  EQU     4
  3192. EXTBIT  EQU     8
  3193.         MOV     DL,0            ;Flag--not ambiguous file name
  3194.         TEST    AL,DRVBIT       ;Use current drive field if default?
  3195.         JNZ     DEFDRV
  3196.         MOV     BYTE PTR ES:[DI],0      ;No - use default drive
  3197. DEFDRV:
  3198.         INC     DI
  3199.         MOV     CX,8
  3200.         TEST    AL,NAMBIT       ;Use current name fiels as defualt?
  3201.         XCHG    AX,BX           ;Save bits in BX
  3202.         MOV     AL," "
  3203.         JZ      FILLB           ;If not, go fill with blanks
  3204.         ADD     DI,CX
  3205.         XOR     CX,CX           ;Don't fill any
  3206. FILLB:
  3207.         REP     STOSB
  3208.         MOV     CL,3
  3209.         TEST    BL,EXTBIT       ;Use current extension as default
  3210.         JZ      FILLB2
  3211.         ADD     DI,CX
  3212.         XOR     CX,CX
  3213. FILLB2:
  3214.         REP     STOSB
  3215.         XCHG    AX,CX           ;Put zero in AX
  3216.         STOSW
  3217.         STOSW                   ;Initialize two words after to zero
  3218.         SUB     DI,16           ;Point back at start
  3219.         TEST    BL,1            ;Scan off separators if not zero
  3220.         JZ      SKPSPC
  3221.         CALL    SCANB           ;Peel off blanks and tabs
  3222.         CALL    DELIM           ;Is it a one-time-only delimiter?
  3223.         JNZ     NOSCAN
  3224.         INC     SI              ;Skip over the delimiter
  3225. SKPSPC:
  3226.         CALL    SCANB           ;Always kill preceding blanks and tabs
  3227. NOSCAN:
  3228.         CALL    GETLET
  3229.         JBE     NODRV           ;Quit if termination character
  3230.         CMP     BYTE PTR[SI],":"        ;Check for potential drive specifier
  3231.         JNZ     NODRV
  3232.         INC     SI              ;Skip over colon
  3233.         SUB     AL,"@"          ;Convert drive letter to binary drive number
  3234.         JBE     BADDRV          ;Valid drive numbers are 1-15
  3235.         CMP     AL,CS:[NUMDRV]
  3236.         JBE     HAVDRV
  3237. BADDRV:
  3238.         MOV     DL,-1
  3239. HAVDRV:
  3240.         STOSB           ;Put drive specifier in first byte
  3241.         INC     SI
  3242.         DEC     DI      ;Counteract next two instructions
  3243. NODRV:
  3244.         DEC     SI      ;Back up
  3245.         INC     DI      ;Skip drive byte
  3246.         MOV     CX,8
  3247.         CALL    GETWORD         ;Get 8-letter file name
  3248.         CMP     BYTE PTR [SI],"."
  3249.         JNZ     NODOT
  3250.         INC     SI              ;Skip over dot if present
  3251.         MOV     CX,3            ;Get 3-letter extension
  3252.         CALL    MUSTGETWORD
  3253. NODOT:
  3254.         LDS     BX,CS:DWORD PTR [SPSAVE]
  3255.         MOV     [BX.SISAVE],SI
  3256.         MOV     AL,DL
  3257.         RET
  3258.  
  3259. NONAM:
  3260.         ADD     DI,CX
  3261.         DEC     SI
  3262.         RET
  3263.  
  3264. GETWORD:
  3265.         CALL    GETLET
  3266.         JBE     NONAM           ;Exit if invalid character
  3267.         DEC     SI
  3268. MUSTGETWORD:
  3269.         CALL    GETLET
  3270.         JBE     FILLNAM
  3271.         JCXZ    MUSTGETWORD
  3272.         DEC     CX
  3273.         CMP     AL,"*"          ;Check for ambiguous file specifier
  3274.         JNZ     NOSTAR
  3275.         MOV     AL,"?"
  3276.         REP     STOSB
  3277. NOSTAR:
  3278.         STOSB
  3279.         CMP     AL,"?"
  3280.         JNZ     MUSTGETWORD
  3281.         OR      DL,1            ;Flag ambiguous file name
  3282.         JMP     MUSTGETWORD
  3283. FILLNAM:
  3284.         MOV     AL," "
  3285.         REP     STOSB
  3286.         DEC     SI
  3287. RET21:  RET
  3288.  
  3289. SCANB:
  3290.         LODSB
  3291.         CALL    SPCHK
  3292.         JZ      SCANB
  3293.         DEC     SI
  3294.         RET
  3295.  
  3296. GETLET:
  3297. ;Get a byte from [SI], convert it to upper case, and compare for delimiter.
  3298. ;ZF set if a delimiter, CY set if a control character (other than TAB).
  3299.         LODSB
  3300.         AND     AL,7FH
  3301.         CMP     AL,"a"
  3302.         JB      CHK
  3303.         CMP     AL,"z"
  3304.         JA      CHK
  3305.         SUB     AL,20H          ;Convert to upper case
  3306. CHK:
  3307.         CMP     AL,"."
  3308.         JZ      RET21
  3309.         CMP     AL,'"'
  3310.         JZ      RET21
  3311.         CMP     AL,"/"
  3312.         JZ      RET21
  3313.         CMP     AL,"["
  3314.         JZ      RET21
  3315.         CMP     AL,"]"
  3316.         JZ      RET21
  3317.  
  3318.         IF      IBM
  3319. DELIM:
  3320.         ENDIF
  3321.         CMP     AL,":"          ;Allow ":" as separator in IBM version
  3322.         JZ      RET21
  3323.         IF      NOT IBM
  3324. DELIM:
  3325.         ENDIF
  3326.  
  3327.         CMP     AL,"+"
  3328.         JZ      RET101
  3329.         CMP     AL,"="
  3330.         JZ      RET101
  3331.         CMP     AL,";"
  3332.         JZ      RET101
  3333.         CMP     AL,","
  3334.         JZ      RET101
  3335. SPCHK:
  3336.         CMP     AL,9            ;Filter out tabs too
  3337.         JZ      RET101
  3338. ;WARNING! " " MUST be the last compare
  3339.         CMP     AL," "
  3340. RET101: RET
  3341.  
  3342. SETVECT: ; Interrupt call 37
  3343.         XOR     BX,BX
  3344.         MOV     ES,BX
  3345.         MOV     BL,AL
  3346.         SHL     BX,1
  3347.         SHL     BX,1
  3348.         MOV     ES:[BX],DX
  3349.         MOV     ES:[BX+2],DS
  3350.         RET
  3351.  
  3352.  
  3353. NEWBASE: ; Interrupt call 38
  3354.         MOV     ES,DX
  3355.         LDS     SI,CS:DWORD PTR [SPSAVE]
  3356.         MOV     DS,[SI.CSSAVE]
  3357.         XOR     SI,SI
  3358.         MOV     DI,SI
  3359.         MOV     AX,DS:[2]
  3360.         MOV     CX,80H
  3361.         REP     MOVSW
  3362.  
  3363. SETMEM:
  3364.  
  3365. ; Inputs:
  3366. ;       AX = Size of memory in paragraphs
  3367. ;       DX = Segment
  3368. ; Function:
  3369. ;       Completely prepares a program base at the
  3370. ;       specified segment.
  3371. ; Outputs:
  3372. ;       DS = DX
  3373. ;       ES = DX
  3374. ;       [0] has INT 20H
  3375. ;       [2] = First unavailable segment ([ENDMEM])
  3376. ;       [5] to [9] form a long call to the entry point
  3377. ;       [10] to [13] have exit address (from INT 22H)
  3378. ;       [14] to [17] have ctrl-C exit address (from INT 23H)
  3379. ;       [18] to [21] have fatal error address (from INT 24H)
  3380. ; DX,BP unchanged. All other registers destroyed.
  3381.  
  3382.         XOR     CX,CX
  3383.         MOV     DS,CX
  3384.         MOV     ES,DX
  3385.         MOV     SI,EXIT
  3386.         MOV     DI,SAVEXIT
  3387.         MOVSW
  3388.         MOVSW
  3389.         MOVSW
  3390.         MOVSW
  3391.         MOVSW
  3392.         MOVSW
  3393.         MOV     ES:[2],AX
  3394.         SUB     AX,DX
  3395.         CMP     AX,MAXDIF
  3396.         JBE     HAVDIF
  3397.         MOV     AX,MAXDIF
  3398. HAVDIF:
  3399.         MOV     BX,ENTRYPOINTSEG
  3400.         SUB     BX,AX
  3401.         SHL     AX,1
  3402.         SHL     AX,1
  3403.         SHL     AX,1
  3404.         SHL     AX,1
  3405.         MOV     DS,DX
  3406.         MOV     DS:[6],AX
  3407.         MOV     DS:[8],BX
  3408.         MOV     DS:[0],20CDH    ;"INT INTTAB"
  3409.         MOV     DS:(BYTE PTR [5]),LONGCALL
  3410.         RET
  3411.  
  3412. DATE16:
  3413.         PUSH    CX
  3414.         CALL    READTIME
  3415.         SHL     CL,1            ;Minutes to left part of byte
  3416.         SHL     CL,1
  3417.         SHL     CX,1            ;Push hours and minutes to left end
  3418.         SHL     CX,1
  3419.         SHL     CX,1
  3420.         SHR     DH,1            ;Count every two seconds
  3421.         OR      CL,DH           ;Combine seconds with hours and minutes
  3422.         MOV     DX,CX
  3423.         POP     CX
  3424.         MOV     AX,WORD PTR [MONTH]     ;Fetch month and year
  3425.         SHL     AL,1                    ;Push month to left to make room for day
  3426.         SHL     AL,1
  3427.         SHL     AL,1
  3428.         SHL     AL,1
  3429.         SHL     AX,1
  3430.         OR      AL,[DAY]
  3431. RET22:  RET
  3432.  
  3433. FOURYEARS       EQU     3*365+366
  3434.  
  3435. READTIME:
  3436. ;Gets time in CX:DX. Figures new date if it has changed.
  3437. ;Uses AX, CX, DX.
  3438.         CALL    FAR PTR BIOSGETTIME
  3439.         CMP     AX,[DAYCNT]     ;See if day count is the same
  3440.         JZ      RET22
  3441.         CMP     AX,FOURYEARS*30 ;Number of days in 120 years
  3442.         JAE     RET22           ;Ignore if too large
  3443.         MOV     [DAYCNT],AX
  3444.         PUSH    SI
  3445.         PUSH    CX
  3446.         PUSH    DX              ;Save time
  3447.         XOR     DX,DX
  3448.         MOV     CX,FOURYEARS    ;Number of days in 4 years
  3449.         DIV     CX              ;Compute number of 4-year units
  3450.         SHL     AX,1
  3451.         SHL     AX,1
  3452.         SHL     AX,1            ;Multiply by 8 (no. of half-years)
  3453.         MOV     CX,AX           ;<240 implies AH=0
  3454.         MOV     SI,OFFSET DOSGROUP:YRTAB        ;Table of days in each year
  3455.         CALL    DSLIDE          ;Find out which of four years we're in
  3456.         SHR     CX,1            ;Convert half-years to whole years
  3457.         JNC     SK              ;Extra half-year?
  3458.         ADD     DX,200
  3459. SK:
  3460.         CALL    SETYEAR
  3461.         MOV     CL,1            ;At least at first month in year
  3462.         MOV     SI,OFFSET DOSGROUP:MONTAB       ;Table of days in each month
  3463.         CALL    DSLIDE          ;Find out which month we're in
  3464.         MOV     [MONTH],CL
  3465.         INC     DX              ;Remainder is day of month (start with one)
  3466.         MOV     [DAY],DL
  3467.         CALL    WKDAY           ;Set day of week
  3468.         POP     DX
  3469.         POP     CX
  3470.         POP     SI
  3471. RET23:  RET
  3472.  
  3473. DSLIDE:
  3474.         MOV     AH,0
  3475. DSLIDE1:
  3476.         LODSB           ;Get count of days
  3477.         CMP     DX,AX           ;See if it will fit
  3478.         JB      RET23           ;If not, done
  3479.         SUB     DX,AX
  3480.         INC     CX              ;Count one more month/year
  3481.         JMP     SHORT DSLIDE1
  3482.  
  3483. SETYEAR:
  3484. ;Set year with value in CX. Adjust length of February for this year.
  3485.         MOV     BYTE PTR [YEAR],CL
  3486. CHKYR:
  3487.         TEST    CL,3            ;Check for leap year
  3488.         MOV     AL,28
  3489.         JNZ     SAVFEB          ;28 days if no leap year
  3490.         INC     AL              ;Add leap day
  3491. SAVFEB:
  3492.         MOV     [MONTAB+1],AL   ;Store for February
  3493.         RET
  3494.  
  3495. ;Days in year
  3496. YRTAB   DB      200,166         ;Leap year
  3497.         DB      200,165
  3498.         DB      200,165
  3499.         DB      200,165
  3500.  
  3501. ;Days of each month
  3502. MONTAB  DB      31              ;January
  3503.         DB      28              ;February--reset each time year changes
  3504.         DB      31              ;March
  3505.         DB      30              ;April
  3506.         DB      31              ;May
  3507.         DB      30              ;June
  3508.         DB      31              ;July
  3509.         DB      31              ;August
  3510.         DB      30              ;September
  3511.         DB      31              ;October
  3512.         DB      30              ;November
  3513.         DB      31              ;December
  3514.  
  3515. GETDATE: ;Function call 42
  3516.         PUSH    CS
  3517.         POP     DS
  3518.         CALL    READTIME        ;Check for rollover to next day
  3519.         MOV     AX,[YEAR]
  3520.         MOV     BX,WORD PTR [DAY]
  3521.         LDS     SI,DWORD PTR [SPSAVE]   ;Get pointer to user registers
  3522.         MOV     [SI.DXSAVE],BX  ;DH=month, DL=day
  3523.         ADD     AX,1980         ;Put bias back
  3524.         MOV     [SI.CXSAVE],AX  ;CX=year
  3525.         MOV     AL,CS:[WEEKDAY]
  3526. RET24:  RET
  3527.  
  3528. SETDATE: ;Function call 43
  3529.         MOV     AL,-1           ;Be ready to flag error
  3530.         SUB     CX,1980         ;Fix bias in year
  3531.         JC      RET24           ;Error if not big enough
  3532.         CMP     CX,119          ;Year must be less than 2100
  3533.         JA      RET24
  3534.         OR      DH,DH
  3535.         JZ      RET24
  3536.         OR      DL,DL
  3537.         JZ      RET24           ;Error if either month or day is 0
  3538.         CMP     DH,12           ;Check against max. month
  3539.         JA      RET24
  3540.         PUSH    CS
  3541.         POP     DS
  3542.         CALL    CHKYR           ;Set Feb. up for new year
  3543.         MOV     AL,DH
  3544.         MOV     BX,OFFSET DOSGROUP:MONTAB-1
  3545.         XLAT                    ;Look up days in month
  3546.         CMP     AL,DL
  3547.         MOV     AL,-1           ;Restore error flag, just in case
  3548.         JB      RET24           ;Error if too many days
  3549.         CALL    SETYEAR
  3550.         MOV     WORD PTR [DAY],DX       ;Set both day and month
  3551.         SHR     CX,1
  3552.         SHR     CX,1
  3553.         MOV     AX,FOURYEARS
  3554.         MOV     BX,DX
  3555.         MUL     CX
  3556.         MOV     CL,BYTE PTR [YEAR]
  3557.         AND     CL,3
  3558.         MOV     SI,OFFSET DOSGROUP:YRTAB
  3559.         MOV     DX,AX
  3560.         SHL     CX,1            ;Two entries per year, so double count
  3561.         CALL    DSUM            ;Add up the days in each year
  3562.         MOV     CL,BH           ;Month of year
  3563.         MOV     SI,OFFSET DOSGROUP:MONTAB
  3564.         DEC     CX              ;Account for months starting with one
  3565.         CALL    DSUM            ;Add up days in each month
  3566.         MOV     CL,BL           ;Day of month
  3567.         DEC     CX              ;Account for days starting with one
  3568.         ADD     DX,CX           ;Add in to day total
  3569.         XCHG    AX,DX           ;Get day count in AX
  3570.         MOV     [DAYCNT],AX
  3571.         CALL    FAR PTR BIOSSETDATE
  3572. WKDAY:
  3573.         MOV     AX,[DAYCNT]
  3574.         XOR     DX,DX
  3575.         MOV     CX,7
  3576.         INC     AX
  3577.         INC     AX              ;First day was Tuesday
  3578.         DIV     CX              ;Compute day of week
  3579.         MOV     [WEEKDAY],DL
  3580.         XOR     AL,AL           ;Flag OK
  3581. RET25:  RET
  3582.  
  3583. DSUM:
  3584.         MOV     AH,0
  3585.         JCXZ    RET25
  3586. DSUM1:
  3587.         LODSB
  3588.         ADD     DX,AX
  3589.         LOOP    DSUM1
  3590.         RET
  3591.  
  3592. GETTIME: ;Function call 44
  3593.         PUSH    CS
  3594.         POP     DS
  3595.         CALL    READTIME
  3596.         LDS     SI,DWORD PTR [SPSAVE]   ;Get pointer to user registers
  3597.         MOV     [SI.DXSAVE],DX
  3598.         MOV     [SI.CXSAVE],CX
  3599.         XOR     AL,AL
  3600. RET26:  RET
  3601.  
  3602. SETTIME: ;Function call 45
  3603. ;Time is in CX:DX in hours, minutes, seconds, 1/100 sec.
  3604.         MOV     AL,-1           ;Flag in case of error
  3605.         CMP     CH,24           ;Check hours
  3606.         JAE     RET26
  3607.         CMP     CL,60           ;Check minutes
  3608.         JAE     RET26
  3609.         CMP     DH,60           ;Check seconds
  3610.         JAE     RET26
  3611.         CMP     DL,100          ;Check 1/100's
  3612.         JAE     RET26
  3613.         CALL    FAR PTR BIOSSETTIME
  3614.         XOR     AL,AL
  3615.         RET
  3616.  
  3617.  
  3618. ; Default handler for division overflow trap
  3619. DIVOV:
  3620.         PUSH    SI
  3621.         PUSH    AX
  3622.         MOV     SI,OFFSET DOSGROUP:DIVMES
  3623.         CALL    OUTMES
  3624.         POP     AX
  3625.         POP     SI
  3626.         INT     23H             ;Use Ctrl-C abort on divide overflow
  3627.         IRET
  3628.  
  3629. CODSIZ  EQU     $-CODSTRT       ;Size of code segment
  3630. CODE    ENDS
  3631.  
  3632.  
  3633. ;***** DATA AREA *****
  3634. CONSTANTS       SEGMENT BYTE
  3635.         ORG     0
  3636. CONSTRT EQU     $               ;Start of constants segment
  3637.  
  3638. IONAME:
  3639.         IF      NOT IBM
  3640.         DB      "PRN ","LST ","NUL ","AUX ","CON "
  3641.         ENDIF
  3642.         IF      IBM
  3643.         DB      "COM1","PRN ","LPT1","NUL ","AUX ","CON "
  3644.         ENDIF
  3645. DIVMES  DB      13,10,"Divide overflow",13,10,"$"
  3646. CARPOS  DB      0
  3647. STARTPOS DB     0
  3648. PFLAG   DB      0
  3649. DIRTYDIR DB     0               ;Dirty buffer flag
  3650. NUMDRV  DB      0       ;Number of drives
  3651. NUMIO   DB      ?       ;Number of disk tables
  3652. VERFLG  DB      0       ;Initialize with verify off
  3653. CONTPOS DW      0
  3654. DMAADD  DW      80H             ;User's disk transfer address (disp/seg)
  3655.         DW      ?
  3656. ENDMEM  DW      ?
  3657. MAXSEC  DW      0
  3658. BUFFER  DW      ?
  3659. BUFSECNO DW     0
  3660. BUFDRVNO DB     -1
  3661. DIRTYBUF DB     0
  3662. BUFDRVBP DW     ?
  3663. DIRBUFID DW     -1
  3664. DAY     DB      0
  3665. MONTH   DB      0
  3666. YEAR    DW      0
  3667. DAYCNT  DW      -1
  3668. WEEKDAY DB      0
  3669. CURDRV  DB      0               ;Default to drive A
  3670. DRVTAB  DW      0               ;Address of start of DPBs
  3671. DOSLEN  EQU     CODSIZ+($-CONSTRT)      ;Size of CODE + CONSTANTS segments
  3672. CONSTANTS       ENDS
  3673.  
  3674. DATA    SEGMENT WORD
  3675. ; Init code overlaps with data area below
  3676.  
  3677.         ORG     0
  3678. INBUF   DB      128 DUP (?)
  3679. CONBUF  DB      131 DUP (?)             ;The rest of INBUF and console buffer
  3680. LASTENT DW      ?
  3681. EXITHOLD DB     4 DUP (?)
  3682. FATBASE DW      ?
  3683. NAME1   DB      11 DUP (?)              ;File name buffer
  3684. ATTRIB  DB      ?
  3685. NAME2   DB      11 DUP (?)
  3686. NAME3   DB      12 DUP (?)
  3687. EXTFCB  DB      ?
  3688. ;WARNING - the following two items are accessed as a word
  3689. CREATING DB     ?
  3690. DELALL  DB      ?
  3691. TEMP    LABEL   WORD
  3692. SPSAVE  DW      ?
  3693. SSSAVE  DW      ?
  3694. CONTSTK DW      ?
  3695. SECCLUSPOS DB   ?       ;Position of first sector within cluster
  3696. DSKERR  DB      ?
  3697. TRANS   DB      ?
  3698. PREREAD DB      ?       ;0 means preread; 1 means optional
  3699. READOP  DB      ?
  3700. THISDRV DB      ?
  3701.  
  3702.         EVEN
  3703. FCB     DW      ?       ;Address of user FCB
  3704. NEXTADD DW      ?
  3705. RECPOS  DB      4 DUP (?)
  3706. RECCNT  DW      ?
  3707. LASTPOS DW      ?
  3708. CLUSNUM DW      ?
  3709. SECPOS  DW      ?       ;Position of first sector accessed
  3710. VALSEC  DW      ?       ;Number of valid (previously written) sectors
  3711. BYTSECPOS DW    ?       ;Position of first byte within sector
  3712. BYTPOS  DB      4 DUP (?)               ;Byte position in file of access
  3713. BYTCNT1 DW      ?       ;No. of bytes in first sector
  3714. BYTCNT2 DW      ?       ;No. of bytes in last sector
  3715. SECCNT  DW      ?       ;No. of whole sectors
  3716. ENTFREE DW      ?
  3717.  
  3718.         DB      80H DUP (?)     ;Stack space
  3719. IOSTACK LABEL   BYTE
  3720.         DB      80H DUP (?)
  3721. DSKSTACK LABEL  BYTE
  3722.  
  3723.         IF      DSKTEST
  3724. NSS     DW      ?
  3725. NSP     DW      ?
  3726.         ENDIF
  3727.  
  3728. DIRBUF LABEL    WORD
  3729.  
  3730. ;Init code below overlaps with data area above
  3731.  
  3732.         ORG     0
  3733.  
  3734. MOVFAT:
  3735. ;This section of code is safe from being overwritten by block move
  3736.         REP     MOVS    BYTE PTR [DI],[SI]
  3737.         CLD
  3738.         MOV     ES:[DMAADD+2],DX
  3739.         MOV     SI,[DRVTAB]     ;Address of first DPB
  3740.         MOV     AL,-1
  3741.         MOV     CL,[NUMIO]      ;Number of DPBs
  3742. FLGFAT:
  3743.         MOV     DI,ES:[SI.FAT]  ;get pointer to FAT
  3744.         DEC     DI              ;Point to dirty byte
  3745.         STOSB                   ;Flag as unused
  3746.         ADD     SI,DPBSIZ       ;Point to next DPB
  3747.         LOOP    FLGFAT
  3748.         MOV     AX,[ENDMEM]
  3749.         CALL    SETMEM          ;Set up segment
  3750.  
  3751. XXX     PROC FAR
  3752.         RET
  3753. XXX     ENDP
  3754.  
  3755. DOSINIT:
  3756.         CLI
  3757.         CLD
  3758.         PUSH    CS
  3759.         POP     ES
  3760.         MOV     ES:[ENDMEM],DX
  3761.         LODSB                   ;Get no. of drives & no. of I/O drivers
  3762.         MOV     ES:[NUMIO],AL
  3763.         MOV     DI,OFFSET DOSGROUP:MEMSTRT
  3764. PERDRV:
  3765.         MOV     BP,DI
  3766.         MOV     AL,ES:[DRVCNT]
  3767.         STOSB           ;DEVNUM
  3768.         LODSB           ;Physical unit no.
  3769.         STOSB           ;DRVNUM
  3770.         CMP     AL,15
  3771.         JA      BADINIT
  3772.         CBW             ;Index into FAT size table
  3773.         SHL     AX,1
  3774.         ADD     AX,OFFSET DOSGROUP:FATSIZTAB
  3775.         XCHG    BX,AX
  3776.         LODSW           ;Pointer to DPT
  3777.         PUSH    SI
  3778.         MOV     SI,AX
  3779.         LODSW
  3780.         STOSW           ;SECSIZ
  3781.         MOV     DX,AX
  3782.         CMP     AX,ES:[MAXSEC]
  3783.         JBE     NOTMAX
  3784.         MOV     ES:[MAXSEC],AX
  3785. NOTMAX:
  3786.         LODSB
  3787.         DEC     AL
  3788.         STOSB           ;CLUSMSK
  3789.         JZ      HAVSHFT
  3790.         CBW
  3791. FIGSHFT:
  3792.         INC     AH
  3793.         SAR     AL,1
  3794.         JNZ     FIGSHFT
  3795.         MOV     AL,AH
  3796. HAVSHFT:
  3797.         STOSB           ;CLUSSHFT
  3798.         MOVSW           ;FIRFAT (= number of reserved sectors)
  3799.         MOVSB           ;FATCNT
  3800.         MOVSW           ;MAXENT
  3801.         MOV     AX,DX           ;SECSIZ again
  3802.         MOV     CL,5
  3803.         SHR     AX,CL
  3804.         MOV     CX,AX           ;Directory entries per sector
  3805.         DEC     AX
  3806.         ADD     AX,ES:[BP.MAXENT]
  3807.         XOR     DX,DX
  3808.         DIV     CX
  3809.         STOSW           ;DIRSEC (temporarily)
  3810.         MOVSW                   ;DSKSIZ (temporarily)
  3811. FNDFATSIZ:
  3812.         MOV     AL,1
  3813.         MOV     DX,1
  3814. GETFATSIZ:
  3815.         PUSH    DX
  3816.         CALL    FIGFATSIZ
  3817.         POP     DX
  3818.         CMP     AL,DL           ;Compare newly computed FAT size with trial
  3819.         JZ      HAVFATSIZ       ;Has sequence converged?
  3820.         CMP     AL,DH           ;Compare with previous trial
  3821.         MOV     DH,DL
  3822.         MOV     DL,AL           ;Shuffle trials
  3823.         JNZ     GETFATSIZ       ;Continue iterations if not oscillating
  3824.         DEC     WORD PTR ES:[BP.DSKSIZ] ;Damp those oscillations
  3825.         JMP     SHORT FNDFATSIZ ;Try again
  3826.  
  3827. BADINIT:
  3828.         MOV     SI,OFFSET DOSGROUP:BADMES
  3829.         CALL    OUTMES
  3830.         STI
  3831.         HLT
  3832.  
  3833. HAVFATSIZ:
  3834.         STOSB                   ;FATSIZ
  3835.         MUL     ES:BYTE PTR[BP.FATCNT]  ;Space occupied by all FATs
  3836.         ADD     AX,ES:[BP.FIRFAT]
  3837.         STOSW                   ;FIRDIR
  3838.         ADD     AX,ES:[BP.DIRSEC]
  3839.         MOV     ES:[BP.FIRREC],AX       ;Destroys DIRSEC
  3840.         CALL    FIGMAX
  3841.         MOV     ES:[BP.MAXCLUS],CX
  3842.         MOV     AX,BX           ;Pointer into FAT size table
  3843.         STOSW                   ;Allocate space for FAT pointer
  3844.         MOV     AL,ES:[BP.FATSIZ]
  3845.         XOR     AH,AH
  3846.         MUL     ES:[BP.SECSIZ]
  3847.         CMP     AX,ES:[BX]      ;Bigger than already allocated
  3848.         JBE     SMFAT
  3849.         MOV     ES:[BX],AX
  3850. SMFAT:
  3851.         POP     SI              ;Restore pointer to init. table
  3852.         MOV     AL,ES:[DRVCNT]
  3853.         INC     AL
  3854.         MOV     ES:[DRVCNT],AL
  3855.         CMP     AL,ES:[NUMIO]
  3856.         JAE     CONTINIT
  3857.         JMP     PERDRV  
  3858.  
  3859. BADINITJ:
  3860.         JMP     BADINIT
  3861.  
  3862. CONTINIT:
  3863.         PUSH    CS
  3864.         POP     DS
  3865. ;Calculate true address of buffers, FATs, free space
  3866.         MOV     BP,[MAXSEC]
  3867.         MOV     AX,OFFSET DOSGROUP:DIRBUF
  3868.         ADD     AX,BP
  3869.         MOV     [BUFFER],AX     ;Start of buffer
  3870.         ADD     AX,BP
  3871.         MOV     [DRVTAB],AX     ;Start of DPBs
  3872.         SHL     BP,1            ;Two sectors - directory and buffer
  3873.         ADD     BP,DI           ;Allocate buffer space
  3874.         ADD     BP,ADJFAC       ;True address of FATs
  3875.         PUSH    BP
  3876.         MOV     SI,OFFSET DOSGROUP:FATSIZTAB
  3877.         MOV     DI,SI
  3878.         MOV     CX,16
  3879. TOTFATSIZ:
  3880.         INC     BP              ;Add one for Dirty byte
  3881.         INC     BP              ;Add one for I/O device number
  3882.         LODSW                   ;Get size of this FAT
  3883.         XCHG    AX,BP
  3884.         STOSW                   ;Save address of this FAT
  3885.         ADD     BP,AX           ;Compute size of next FAT
  3886.         CMP     AX,BP           ;If size was zero done
  3887.         LOOPNZ  TOTFATSIZ
  3888.         MOV     AL,15
  3889.         SUB     AL,CL           ;Compute number of FATs used
  3890.         MOV     [NUMDRV],AL
  3891.         XOR     AX,AX           ;Set zero flag
  3892.         REPZ    SCASW           ;Make sure all other entries are zero
  3893.         JNZ     BADINITJ
  3894.         ADD     BP,15           ;True start of free space
  3895.         MOV     CL,4
  3896.         SHR     BP,CL           ;First free segment
  3897.         MOV     DX,CS
  3898.         ADD     DX,BP
  3899.         MOV     BX,0FH
  3900.         MOV     CX,[ENDMEM]
  3901.         CMP     CX,1            ;Use memory scan?
  3902.         JNZ     SETEND
  3903.         MOV     CX,DX           ;Start scanning just after DOS
  3904. MEMSCAN:
  3905.         INC     CX
  3906.         JZ      SETEND
  3907.         MOV     DS,CX
  3908.         MOV     AL,[BX]
  3909.         NOT     AL
  3910.         MOV     [BX],AL
  3911.         CMP     AL,[BX]
  3912.         NOT     AL
  3913.         MOV     [BX],AL
  3914.         JZ      MEMSCAN
  3915. SETEND:
  3916.         IF      HIGHMEM
  3917.         SUB     CX,BP
  3918.         MOV     BP,CX           ;Segment of DOS
  3919.         MOV     DX,CS           ;Program segment
  3920.         ENDIF
  3921.         IF      NOT HIGHMEM
  3922.         MOV     BP,CS
  3923.         ENDIF
  3924. ; BP has segment of DOS (whether to load high or run in place)
  3925. ; DX has program segment (whether after DOS or overlaying DOS)
  3926. ; CX has size of memory in paragraphs (reduced by DOS size if HIGHMEM)
  3927.         MOV     CS:[ENDMEM],CX
  3928.         IF      HIGHMEM
  3929.         MOV     ES,BP
  3930.         XOR     SI,SI
  3931.         MOV     DI,SI
  3932.         MOV     CX,(DOSLEN+1)/2
  3933.         PUSH    CS
  3934.         POP     DS
  3935.         REP MOVSW               ;Move DOS to high memory
  3936.         ENDIF
  3937.         XOR     AX,AX
  3938.         MOV     DS,AX
  3939.         MOV     ES,AX
  3940.         MOV     DI,INTBASE
  3941.         MOV     AX,OFFSET DOSGROUP:QUIT
  3942.         STOSW                   ;Set abort address--displacement
  3943.         MOV     AX,BP
  3944.         MOV     BYTE PTR DS:[ENTRYPOINT],LONGJUMP
  3945.         MOV     WORD PTR DS:[ENTRYPOINT+1],OFFSET DOSGROUP:ENTRY
  3946.         MOV     WORD PTR DS:[ENTRYPOINT+3],AX
  3947.         MOV     WORD PTR DS:[0],OFFSET DOSGROUP:DIVOV   ;Set default divide trap address
  3948.         MOV     DS:[2],AX
  3949.         MOV     CX,9
  3950.         REP STOSW               ;Set 5 segments (skip 2 between each)
  3951.         MOV     WORD PTR DS:[INTBASE+4],OFFSET DOSGROUP:COMMAND
  3952.         MOV     WORD PTR DS:[INTBASE+12],OFFSET DOSGROUP:IRET   ;Ctrl-C exit
  3953.         MOV     WORD PTR DS:[INTBASE+16],OFFSET DOSGROUP:IRET   ;Fatal error exit
  3954.         MOV     AX,OFFSET BIOSREAD
  3955.         STOSW
  3956.         MOV     AX,BIOSSEG
  3957.         STOSW
  3958.         STOSW                   ;Add 2 to DI
  3959.         STOSW
  3960.         MOV     WORD PTR DS:[INTBASE+18H],OFFSET BIOSWRITE
  3961.         MOV     WORD PTR DS:[EXIT],100H
  3962.         MOV     WORD PTR DS:[EXIT+2],DX
  3963.         IF      NOT IBM
  3964.         MOV     SI,OFFSET DOSGROUP:HEADER
  3965.         CALL    OUTMES
  3966.         ENDIF
  3967.         PUSH    CS
  3968.         POP     DS
  3969.         PUSH    CS
  3970.         POP     ES
  3971. ;Move the FATs into position
  3972.         MOV     AL,[NUMIO]
  3973.         CBW
  3974.         XCHG    AX,CX
  3975.         MOV     DI,OFFSET DOSGROUP:MEMSTRT.FAT
  3976. FATPOINT:
  3977.         MOV     SI,WORD PTR [DI]        ;Get address within FAT address table
  3978.         MOVSW                           ;Set address of this FAT
  3979.         ADD     DI,DPBSIZ-2             ;Point to next DPB
  3980.         LOOP    FATPOINT
  3981.         POP     CX                      ;True address of first FAT
  3982.         MOV     SI,OFFSET DOSGROUP:MEMSTRT      ;Place to move DPBs from
  3983.         MOV     DI,[DRVTAB]             ;Place to move DPBs to
  3984.         SUB     CX,DI                   ;Total length of DPBs
  3985.         CMP     DI,SI
  3986.         JBE     MOVJMP                  ;Are we moving to higher or lower memory?
  3987.         DEC     CX                      ;Move backwards to higher memory
  3988.         ADD     DI,CX
  3989.         ADD     SI,CX
  3990.         INC     CX
  3991.         STD
  3992. MOVJMP:
  3993.         MOV     ES,BP
  3994.         JMP     MOVFAT
  3995.  
  3996. FIGFATSIZ:
  3997.         MUL     ES:BYTE PTR[BP.FATCNT]
  3998.         ADD     AX,ES:[BP.FIRFAT]
  3999.         ADD     AX,ES:[BP.DIRSEC]
  4000. FIGMAX:
  4001. ;AX has equivalent of FIRREC
  4002.         SUB     AX,ES:[BP.DSKSIZ]
  4003.         NEG     AX
  4004.         MOV     CL,ES:[BP.CLUSSHFT]
  4005.         SHR     AX,CL
  4006.         INC     AX
  4007.         MOV     CX,AX           ;MAXCLUS
  4008.         INC     AX
  4009.         MOV     DX,AX
  4010.         SHR     DX,1
  4011.         ADC     AX,DX           ;Size of FAT in bytes
  4012.         MOV     SI,ES:[BP.SECSIZ]
  4013.         ADD     AX,SI
  4014.         DEC     AX
  4015.         XOR     DX,DX
  4016.         DIV     SI
  4017.         RET
  4018.  
  4019. BADMES:
  4020.         DB      13,10,"INIT TABLE BAD",13,10,"$"
  4021.  
  4022. FATSIZTAB:
  4023.         DW      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  4024.  
  4025. DRVCNT  DB      0
  4026.  
  4027. MEMSTRT LABEL   WORD
  4028. ADJFAC  EQU     DIRBUF-MEMSTRT
  4029. DATA    ENDS
  4030.         END
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement