home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / Assembly / DISK_IO.ASM < prev    next >
Assembly Source File  |  1986-10-07  |  32KB  |  941 lines

  1. CGROUP    GROUP    CODE_SEG, DATA_SEG
  2.     ASSUME    CS:CGROUP, DS:CGROUP
  3.  
  4.  
  5. ;-----------------------------------------------------------------------;
  6. ; This file contains the procedures to handle disk I/O, such as reading    ;
  7. ; and writing a disk sector.  It also contains procedures that handle    ;
  8. ; reading and writing of sectors within a file.                ;
  9. ;                                    ;
  10. ; One word of caution.  As with the version in the book, Dskpatch    ;
  11. ; assumes that sectors are 512 bytes.  If your machine uses longer    ;
  12. ; sectors, you may want to modify Dskpatch so that it handles longer    ;
  13. ; sectors.  In any case, the procedures that read and write file    ;
  14. ; "sectors" are not dependent on the actual sector size.        ;
  15. ;                                    ;
  16. ; Here is a list of procedure in this file:                ;
  17. ;                                    ;
  18. ; INIT_DISK            Initializes variables, etc.        ;
  19. ; TRAP_DISK_ERRORS        Handles disk errors for file functions    ;
  20. ; WRITE_IO_ERROR        Writes or clears the error message    ;
  21. ; WRITE_ERROR_MESSAGE        Writes an error message on screen    ;
  22. ; CLEAR_ERROR_MESSAGE        Clears the last error message        ;
  23. ; READ_SECTOR            Read logical or file sector        ;
  24. ; READ_LOGICAL_SECTOR        Read a logical disk sector        ;
  25. ; WRITE_SECTOR            Write logical or file sector        ;
  26. ; WRITE_LOGICAL_SECTOR        Writes a logical sector to the disk    ;
  27. ; PREVIOUS_SECTOR        Read the previous sector from disk/file    ;
  28. ; NEXT_SECTOR            Read the next sector from disk/file    ;
  29. ; CHANGE_DISK_DRIVE        Change to a different disk drive    ;
  30. ; READ_SECTOR_NUMBER        Change to a sector, by number        ;
  31. ; OPEN_NEW_FILE            Open a file for reading and writing    ;
  32. ; READ_FILE_NAME        Read the name of the file to open    ;
  33. ; OPEN_FILE            Actually open the file            ;
  34. ; QUIT_FILE_MODE        Closes the open file            ;
  35. ; READ_OFFSET_NUMBER        Ask for the sector number within a file    ;
  36. ; READ_FILE_SECTOR        Actually read a sector from the file    ;
  37. ; SET_FILE_POINTER        Move to the start of a sector in file    ;
  38. ; WRITE_FILE_SECTOR        Writes a file's sector back to the disk    ;
  39. ;-----------------------------------------------------------------------;
  40.  
  41.  
  42. CODE_SEG    SEGMENT PUBLIC
  43.  
  44.     public    disk_error_flag, disk_error_code
  45. DISK_ERROR_FLAG        DB    0    ;Used to keep track of errors
  46. DISK_ERROR_CODE        DB    0    ;Error code from disk operation
  47.  
  48. DATA_SEG    SEGMENT PUBLIC
  49.     EXTRN    ERROR_MESSAGE_LINE_NO:BYTE
  50.  
  51. ERROR_CODE_TABLE    LABEL    WORD
  52.     DW    OFFSET CGROUP:ERROR_0
  53.     DW    OFFSET CGROUP:ERROR_1
  54.     DW    OFFSET CGROUP:ERROR_2
  55.     DW    OFFSET CGROUP:ERROR_3
  56.     DW    OFFSET CGROUP:ERROR_4
  57.     DW    OFFSET CGROUP:ERROR_5
  58.     DW    OFFSET CGROUP:ERROR_6
  59.     DW    OFFSET CGROUP:ERROR_7
  60.     DW    OFFSET CGROUP:ERROR_8
  61.     DW    OFFSET CGROUP:ERROR_9
  62.     DW    OFFSET CGROUP:ERROR_A
  63.     DW    OFFSET CGROUP:ERROR_B
  64.     DW    OFFSET CGROUP:ERROR_C
  65.     DW    OFFSET CGROUP:ERROR_D    ;Used by File I/O procedure
  66.     DW    OFFSET CGROUP:ERROR_E    ;Used by File I/O procedure
  67.     DW    OFFSET CGROUP:ERROR_F    ;Used by READ_FILE_SECTOR
  68.     DW    OFFSET CGROUP:ERROR_10    ;Used by FILE_WRITE_SECTOR
  69.  
  70. ERROR_0        DB    'Write attempt on write-protected diskette',0
  71. ERROR_1        DB    'Unknown unit',0
  72. ERROR_2        DB    'Drive not ready',0
  73. ERROR_3        DB    'Unknown command',0
  74. ERROR_4        DB    'Data error (CRC)',0
  75. ERROR_5        DB    'Bad request structure length',0
  76. ERROR_6        DB    'Seek error',0
  77. ERROR_7        DB    'Unknown media type',0
  78. ERROR_8        DB    'Sector not found',0
  79. ERROR_9        DB    'Printer out of paper',0
  80. ERROR_A        DB    'Write fault',0
  81. ERROR_B        DB    'Read fault',0
  82. ERROR_C        DB    'General failure',0
  83. ERROR_D        DB    'Error reading file',0    ;Used by File I/O procedures
  84. ERROR_E        DB    'File not found',0    ;Used by File I/O procedures
  85. ERROR_F        DB    'Read past end of file',0    ;Used by READ_FILE_S...
  86. ERROR_10    DB    'No room on disk',0    ;Used by WRITE_FILE_SECTOR
  87.  
  88. READING_MESSAGE    DB    ' Reading...',0
  89. WRITING_MESSAGE    DB    ' Writing...',0
  90. PRESS_KEY    DB    'Press any key to continue... ',0
  91.  
  92. BYTES_READ    DW    ?        ;Bytes read by READ_FILE_SECTOR
  93. DATA_SEG    ENDS
  94.  
  95.  
  96.     PUBLIC    INIT_DISK
  97. DATA_SEG    SEGMENT PUBLIC
  98.     EXTRN    DISK_DRIVE_NO:BYTE
  99. DATA_SEG    ENDS
  100. ;-----------------------------------------------------------------------;
  101. ; This procedure initializes several things that Disk Patch needs to    ;
  102. ; function properly:                            ;
  103. ;                                    ;
  104. ;    1.  It sets DISK_DRIVE_NO to the number of the current drive,    ;
  105. ;        rather than simply drive A:.  This is useful if you start    ;
  106. ;        Dskpatch from a hard disk with no floppy disk in the drive.    ;
  107. ;                                    ;
  108. ;    2.  It tells DOS to call TRAP_DISK_ERRORS whenever there is a    ;
  109. ;        disk error and we're reading a file.  We use this so that    ;
  110. ;        we can report disk errors.                    ;
  111. ;                                    ;
  112. ; Writes:    DISK_DRIVE_NO                        ;
  113. ;-----------------------------------------------------------------------;
  114. INIT_DISK    PROC    NEAR
  115.     MOV    AH,19h            ;Ask DOS for the disk drive number
  116.     INT    21h
  117.     MOV    DISK_DRIVE_NO,AL    ;Save this drive number
  118.  
  119.     MOV    AL,24H            ;Set INT 24H (ERROR) vector
  120.     MOV    AH,25H            ;Set vector function
  121.     LEA    DX,TRAP_DISK_ERRORS
  122.     INT    21H
  123.  
  124.     RET
  125. INIT_DISK    ENDP
  126.  
  127.  
  128.     PUBLIC    TRAP_DISK_ERRORS
  129. ;-----------------------------------------------------------------------;
  130. ; DOS calls this procedure in case of INT 21h errors using an INT 24h    ;
  131. ; call.                                    ;
  132. ;                                    ;
  133. ; This procedure saves the error code in DISK_ERROR_CODE, then returns    ;
  134. ; to DOS with AL set to 0.  This tells DOS to "ignore" the error.    ;
  135. ; Dskpatch checks the error flag for errors after making INT 21h calls.    ;
  136. ;                                    ;
  137. ; Writes:    DISK_ERROR_FLAG, DISK_ERROR_CODE            ;
  138. ;-----------------------------------------------------------------------;
  139. TRAP_DISK_ERRORS    PROC    FAR
  140.     PUSH    AX
  141.     MOV    AX,DI            ;Get error code into AL
  142.     MOV    CS:DISK_ERROR_FLAG,1    ;Set the error flag
  143.     MOV    CS:DISK_ERROR_CODE,AL    ;Save this disk error code
  144.     POP    AX
  145.     MOV    AL,0            ;Tell DOS to ignore this error
  146.     IRET                ;Let DOS return to Dskpatch
  147. TRAP_DISK_ERRORS    ENDP
  148.  
  149.  
  150.  
  151.     PUBLIC    WRITE_IO_ERROR
  152. ;-----------------------------------------------------------------------;
  153. ; This procedure writes an error message to the error message line.    ;
  154. ;                                    ;
  155. ; Uses:        WRITE_ERROR_MESSAGE, CLEAR_ERROR_MESSAGE        ;
  156. ; Reads:    DISK_ERROR_FLAG, DISK_ERROR_CODE, ERROR_CODE_TABLE    ;
  157. ;-----------------------------------------------------------------------;
  158. WRITE_IO_ERROR    PROC    NEAR
  159.     PUSH    BX
  160.     PUSH    DX
  161.  
  162.     CMP    DISK_ERROR_FLAG,1    ;Was there an error?
  163.     JE    WRITE_MESSAGE        ;Yes, then write the message
  164.     CALL    CLEAR_ERROR_MESSAGE    ;No, then clear the message
  165.     JMP    DONE_WRITE_IO_ERROR    ;We're all done here
  166. WRITE_MESSAGE:
  167.     MOV    BL,DISK_ERROR_CODE    ;Get the error code
  168.     XOR    BH,BH            ;Convert to a word
  169.     SHL    BX,1            ;Multiply by 2 for word look-up
  170.     MOV    DX,ERROR_CODE_TABLE[BX]    ;Get address of error message
  171.     CALL    WRITE_ERROR_MESSAGE    ;Display the error message
  172.  
  173. DONE_WRITE_IO_ERROR:
  174.     POP    DX
  175.     POP    BX
  176.     RET
  177. WRITE_IO_ERROR    ENDP
  178.  
  179.  
  180.     PUBLIC    WRITE_ERROR_MESSAGE
  181.     EXTRN    GOTO_XY:NEAR
  182.     EXTRN    WRITE_STRING:NEAR
  183.     EXTRN    CLEAR_TO_END_OF_LINE:NEAR
  184.     EXTRN    WRITE_ATTRIBUTE_N_TIMES:NEAR
  185. ;-----------------------------------------------------------------------;
  186. ; This procedure writes an error message in the message area near the    ;
  187. ; bottom of the screen.                            ;
  188. ;                                    ;
  189. ;    DS:DX        Address of the error message            ;
  190. ;                                    ;
  191. ; Uses:        GOTO_XY, WRITE_STRING, CLEAR_TO_END_OF_LINE        ;
  192. ;        WRITE_ATTRIBUTE_N_TIMES                    ;
  193. ; Reads:    ERROR_MESSAGE_LINE_NO                    ;
  194. ;-----------------------------------------------------------------------;
  195. WRITE_ERROR_MESSAGE    PROC    NEAR
  196.     PUSH    CX
  197.     PUSH    DX
  198.     MOV    CX,DX            ;Put the string address into CX
  199.     MOV    DH,ERROR_MESSAGE_LINE_NO    ;Get the line number
  200.     MOV    DL,30            ;Indent message 30 spaces
  201.     CALL    GOTO_XY            ;Move cursor to start of the message
  202.     XCHG    CX,DX            ;Put the string address back into DX
  203.     CALL    WRITE_STRING        ;Write the string here
  204.     CALL    CLEAR_TO_END_OF_LINE    ;Then clear the rest of the line
  205.     XCHG    CX,DX            ;Put the coordinates back into DX
  206.     CALL    GOTO_XY            ;Move to the start of the message
  207.     MOV    DL,0Fh            ;High-intensity attribute
  208.     MOV    CX,49            ;Set the entire line to bright
  209.     CALL    WRITE_ATTRIBUTE_N_TIMES
  210.     POP    DX
  211.     POP    CX
  212.     RET
  213. WRITE_ERROR_MESSAGE    ENDP
  214.  
  215.  
  216.     PUBLIC    CLEAR_ERROR_MESSAGE
  217.     EXTRN    GOTO_XY:NEAR
  218.     EXTRN    CLEAR_TO_END_OF_LINE:NEAR
  219. ;-----------------------------------------------------------------------;
  220. ; This procedure clears the error message which appears after a disk    ;
  221. ; error.                                ;
  222. ;                                    ;
  223. ; Uses:        GOTO_XY, CLEAR_TO_END_OF_LINE                ;
  224. ; Reads:    ERROR_MESSAGE_LINE_NO                    ;
  225. ;-----------------------------------------------------------------------;
  226. CLEAR_ERROR_MESSAGE    PROC    NEAR
  227.     PUSH    DX
  228.     MOV    DH,ERROR_MESSAGE_LINE_NO ;Get the line number for the error
  229.     XOR    DL,DL            ;Start of the message line
  230.     CALL    GOTO_XY            ;Move to start of error message line
  231.     CALL    CLEAR_TO_END_OF_LINE    ;Clear the entire line
  232.     POP    DX
  233.     RET
  234. CLEAR_ERROR_MESSAGE    ENDP
  235.  
  236.  
  237.     PUBLIC    READ_SECTOR
  238. DATA_SEG    SEGMENT PUBLIC
  239.     EXTRN    DISK_DRIVE_NO:BYTE
  240.     EXTRN    CURRENT_SECTOR_NO:WORD
  241.     EXTRN    FILE_FLAG:BYTE
  242. DATA_SEG    ENDS
  243. ;-----------------------------------------------------------------------;
  244. ;  This procedure reads one sector (512 bytes) into SECTOR.        ;
  245. ;                                    ;
  246. ; Uses:        CLEAR_SECTOR, READ_LOGICAL_SECTOR, READ_FILE_SECTOR    ;
  247. ;        WRITE_IO_ERROR                        ;
  248. ; Reads:    DISK_ERROR_FLAG, FILE_FLAG                ;
  249. ; Writes:    DISK_ERROR_FLAG                        ;
  250. ;-----------------------------------------------------------------------;
  251. READ_SECTOR    PROC    NEAR
  252.     MOV    DISK_ERROR_FLAG,0    ;Clear the disk error flag before read
  253.     CALL    CLEAR_SECTOR        ;Clear the sector before we start
  254.  
  255.     CMP    FILE_FLAG,1        ;Are we in file mode?
  256.     JE    FILE_READ        ;Yes, then read sector from file
  257.     CALL    READ_LOGICAL_SECTOR    ;No, read a logical disk sector
  258.     JMP    JUST_READ_SECTOR    ;Now check for errors
  259. FILE_READ:
  260.     CALL    READ_FILE_SECTOR    ;Read a sector from the file
  261.  
  262. JUST_READ_SECTOR:
  263.     CMP    DISK_ERROR_FLAG,1    ;Was there a disk error?
  264.     JNE    DONE_READ_SECTOR    ;No, then we're all done
  265.     CALL    CLEAR_SECTOR        ;Yes, then clear SECTOR
  266. DONE_READ_SECTOR:
  267.     CALL    WRITE_IO_ERROR        ;Write or clear error message
  268.     RET
  269. READ_SECTOR    ENDP
  270.  
  271.  
  272.     PUBLIC    CLEAR_SECTOR
  273. DATA_SEG    SEGMENT PUBLIC
  274.     EXTRN    SECTOR:BYTE
  275. DATA_SEG    ENDS
  276. ;-----------------------------------------------------------------------;
  277. ; This procedure sets SECTOR to all 0s.  Call this procedure before    ;
  278. ; you try a read a sector so that the sector will be all 0s if there    ;
  279. ; is an error.                                ;
  280. ;                                    ;
  281. ; Writes:    SECTOR                            ;
  282. ;-----------------------------------------------------------------------;
  283. CLEAR_SECTOR    PROC    NEAR
  284.     PUSH    AX            ;Clear SECTOR to all 0s
  285.     PUSH    CX
  286.     PUSH    DI
  287.     LEA    DI,SECTOR        ;Point to the sector buffer
  288.     MOV    CX,512            ;Number of bytes in one sector
  289.     CLD                ;Set direction for increment
  290.     MOV    AL,0            ;Store zeros in SECTOR
  291. REP    STOSB                ;Clear SECTOR
  292.     POP    DI
  293.     POP    CX
  294.     POP    AX
  295.     RET
  296. CLEAR_SECTOR    ENDP
  297.  
  298.  
  299.     PUBLIC    READ_LOGICAL_SECTOR
  300. DATA_SEG    SEGMENT PUBLIC
  301.     EXTRN    DISK_DRIVE_NO:BYTE
  302.     EXTRN    CURRENT_SECTOR_NO:WORD
  303.     EXTRN    SECTOR:BYTE
  304. DATA_SEG    ENDS
  305. ;-----------------------------------------------------------------------;
  306. ; This procedure reads a logical sector from the disk, using the DOS    ;
  307. ; function 25h.                                ;
  308. ;                                    ;
  309. ; Reads:    DISK_DRIVE_NO, CURRENT_SECTOR_NO            ;
  310. ; Writes:    SECTOR, DISK_ERROR_FLAG, DISK_ERROR_CODE        ;
  311. ;-----------------------------------------------------------------------;
  312. READ_LOGICAL_SECTOR    PROC    NEAR
  313.     PUSH    AX
  314.     PUSH    BX
  315.     PUSH    CX
  316.     PUSH    DX
  317.     MOV    AL,DISK_DRIVE_NO    ;Drive number
  318.     MOV    CX,1            ;Read only 1 sector
  319.     MOV    DX,CURRENT_SECTOR_NO    ;Logical sector number
  320.     LEA    BX,SECTOR        ;Where to store this sector
  321.     INT    25h            ;Read the sector
  322.     JNC    READ_LOGICAL_NO_ERROR    ;There wasn't an error, continue
  323.     MOV    DISK_ERROR_FLAG,1    ;Set the error flag
  324.     MOV    DISK_ERROR_CODE,AL    ;And save the error code
  325. READ_LOGICAL_NO_ERROR:
  326.     POPF                ;Discard flags put on stack by INT 25h
  327.     POP    DX
  328.     POP    CX
  329.     POP    BX
  330.     POP    AX
  331.     RET
  332. READ_LOGICAL_SECTOR    ENDP
  333.  
  334.  
  335.     PUBLIC    WRITE_SECTOR
  336.     EXTRN    WRITE_STRING:NEAR, WRITE_PROMPT_LINE:NEAR
  337. DATA_SEG    SEGMENT PUBLIC
  338.     EXTRN    FILE_FLAG:BYTE
  339. DATA_SEG    ENDS
  340. ;-----------------------------------------------------------------------;
  341. ; This procedure writes a sector back to the disk.  Note, if the last    ;
  342. ; read resulted in an error (in which case the error flag will still    ;
  343. ; be set) this procedure does nothing.                    ;
  344. ;                                    ;
  345. ; Uses:        WRITE_IO_ERROR, WRITE_STRING, WRITE_EDITOR_PROMPT    ;
  346. ;        WRITE_LOGICAL_SECTOR, WRITE_FILE_SECTOR            ;
  347. ; Reads:    FILE_FLAG, WRITING_MESSAGE, DISK_ERROR_FLAG        ;
  348. ;-----------------------------------------------------------------------;
  349. WRITE_SECTOR    PROC    NEAR
  350.     PUSH    AX
  351.     CMP    DISK_ERROR_FLAG,0    ;Was there a disk error?
  352.     JNE    DONT_WRITE_SECTOR    ;Yes, then don't write a sector
  353.  
  354.     LEA    DX,WRITING_MESSAGE    ;Provide feedback while we write
  355.     CALL    WRITE_STRING
  356.  
  357.     CMP    FILE_FLAG,1        ;Are we in file mode?
  358.     JE    FILE_WRITE        ;Yes, then write sector to file
  359.     CALL    WRITE_LOGICAL_SECTOR    ;No, write a logical disk sector
  360.     JMP    JUST_WROTE_SECTOR    ;Now check for errors
  361. FILE_WRITE:
  362.     CALL    WRITE_FILE_SECTOR    ;Write a sector to the file
  363.  
  364. JUST_WROTE_SECTOR:
  365.     CMP    DISK_ERROR_FLAG,1    ;Was there a disk error?
  366.     JE    WRITE_SECTOR_ERROR    ;Yes, then report it
  367.  
  368. DONE_WRITE_SECTOR:
  369.     CALL    WRITE_IO_ERROR        ;Write or clear error message
  370.     CALL    WRITE_EDITOR_PROMPT
  371. DONT_WRITE_SECTOR:
  372.     POP    AX
  373.     RET
  374.  
  375. WRITE_SECTOR_ERROR:
  376.     CALL    WRITE_IO_ERROR        ;Display the error message
  377.     LEA    DX,PRESS_KEY        ;Display "Press any key..." message
  378.     CALL    WRITE_PROMPT_LINE    ;Display this prompt
  379.     CALL    READ_CHAR        ;And read a character
  380.     MOV    DISK_ERROR_FLAG,0    ;Clear the error flag
  381.     JMP    DONE_WRITE_SECTOR    ;We're all done
  382. WRITE_SECTOR    ENDP
  383.  
  384.  
  385.     PUBLIC    WRITE_LOGICAL_SECTOR
  386.     EXTRN    WRITE_EDITOR_PROMPT:NEAR
  387. DATA_SEG    SEGMENT PUBLIC
  388.     EXTRN    SECTOR:BYTE
  389.     EXTRN    DISK_DRIVE_NO:BYTE
  390.     EXTRN    CURRENT_SECTOR_NO:WORD
  391. DATA_SEG    ENDS
  392. ;-----------------------------------------------------------------------;
  393. ; This procedure writes a logical sector to the disk drive.  Not, if    ;
  394. ; the last read resulted in an error, this procedure won't write a    ;
  395. ; sector to the disk.                            ;
  396. ;                                    ;
  397. ; Reads:    DISK_DRIVE_NO, CURRENT_SECTOR_NO            ;
  398. ; Writes:    SECTOR, DISK_ERROR_FLAG, DISK_ERROR_CODE        ;
  399. ;-----------------------------------------------------------------------;
  400. WRITE_LOGICAL_SECTOR    PROC    NEAR
  401.     PUSH    AX
  402.     PUSH    BX
  403.     PUSH    CX
  404.     PUSH    DX
  405.     MOV    AL,DISK_DRIVE_NO    ;Drive number
  406.     MOV    CX,1            ;Write 1 sector
  407.     MOV    DX,CURRENT_SECTOR_NO    ;Logical sector
  408.     LEA    BX,SECTOR        ;Get address of our sector
  409.     INT    26H            ;Write the sector to disk
  410.     JNC    WRITE_LOGICAL_NO_ERROR    ;There wasn't an error, continue
  411.     MOV    DISK_ERROR_FLAG,1    ;Set the error flag
  412.     MOV    DISK_ERROR_CODE,AL    ;Save the error code
  413. WRITE_LOGICAL_NO_ERROR:
  414.     POPF                ;Discard the flag information
  415.     POP    DX
  416.     POP    CX
  417.     POP    BX
  418.     POP    AX
  419.     RET
  420. WRITE_LOGICAL_SECTOR    ENDP
  421.  
  422.  
  423.     PUBLIC    PREVIOUS_SECTOR
  424.     EXTRN    INIT_SEC_DISP:NEAR
  425.     EXTRN    WRITE_STRING:NEAR
  426.     EXTRN    WRITE_EDITOR_PROMPT:NEAR
  427. DATA_SEG    SEGMENT PUBLIC
  428.     EXTRN    CURRENT_SECTOR_NO:WORD
  429. DATA_SEG    ENDS
  430. ;-----------------------------------------------------------------------;
  431. ; This procedure reads the previous sector, if possible            ;
  432. ;                                    ;
  433. ; Uses:        WRITE_STRING, WRITE_EDITOR_PROMPT, INIT_SEC_DISP    ;
  434. ; Reads:    CURRENT_SECTOR_NO, READING_MESSAGE            ;
  435. ; Writes:    CURRENT_SECTOR_NO                    ;
  436. ;-----------------------------------------------------------------------;
  437. PREVIOUS_SECTOR        PROC    NEAR
  438.     PUSH    AX
  439.     PUSH    DX
  440.     MOV    AX,CURRENT_SECTOR_NO    ;Get current sector number
  441.     OR    AX,AX            ;Is sector number zero?
  442.     JZ    DONT_DECREMENT_SECTOR    ;Yes, then we're all done
  443.     DEC    AX            ;No, then subtract one
  444.     MOV    CURRENT_SECTOR_NO,AX    ;Save new sector number
  445.     LEA    DX,READING_MESSAGE    ;Provide feedback while we're reading
  446.     CALL    WRITE_STRING
  447.     CALL    INIT_SEC_DISP        ;Display the new screen
  448.     CALL    WRITE_EDITOR_PROMPT    ;Display the editor prompt
  449. DONT_DECREMENT_SECTOR:
  450.     POP    DX
  451.     POP    AX
  452.     RET
  453. PREVIOUS_SECTOR        ENDP
  454.  
  455.  
  456.     PUBLIC    NEXT_SECTOR
  457.     EXTRN    INIT_SEC_DISP:NEAR
  458.     EXTRN    WRITE_STRING:NEAR
  459.     EXTRN    WRITE_EDITOR_PROMPT:NEAR
  460. DATA_SEG    SEGMENT PUBLIC
  461.     EXTRN    CURRENT_SECTOR_NO:WORD
  462. DATA_SEG    ENDS
  463. ;-----------------------------------------------------------------------;
  464. ; Read the next sector.                            ;
  465. ;                                    ;
  466. ; Uses:        WRITE_EDITOR_PROMPT, INIT_SEC_DISP, WRITE_STRING    ;
  467. ; Reads:    CURRENT_SECTOR_NO, READING_MESSAGE            ;
  468. ; Writes:    CURRENT_SECTOR_NO                    ;
  469. ;-----------------------------------------------------------------------;
  470. NEXT_SECTOR    PROC    NEAR
  471.     PUSH    AX
  472.     PUSH    DX
  473.     MOV    AX,CURRENT_SECTOR_NO    ;Get the current sector number
  474.     INC    AX            ;Move to next sector
  475.     MOV    CURRENT_SECTOR_NO,AX    ;Save this new number
  476.     LEA    DX,READING_MESSAGE    ;Provide feedback while we read
  477.     CALL    WRITE_STRING
  478.     CALL    INIT_SEC_DISP        ;Display the new screen
  479.     CALL    WRITE_EDITOR_PROMPT
  480.     POP    DX
  481.     POP    AX
  482.     RET
  483. NEXT_SECTOR    ENDP
  484.  
  485.  
  486.     PUBLIC    CHANGE_DISK_DRIVE
  487.     EXTRN    READ_BYTE:NEAR
  488.     EXTRN    WRITE_STRING:NEAR
  489.     EXTRN    CHAR_TO_UPPER:NEAR
  490.     EXTRN    WRITE_PROMPT_LINE:NEAR
  491.     EXTRN    WRITE_EDITOR_PROMPT:NEAR
  492.     EXTRN    INIT_SEC_DISP:NEAR
  493. DATA_SEG    SEGMENT PUBLIC
  494.     EXTRN    DISK_DRIVE_NO:BYTE, DISK_PROMPT:BYTE
  495.     EXTRN    FILE_FLAG:BYTE, CURRENT_SECTOR_NO:WORD
  496. DATA_SEG    ENDS
  497. ;-----------------------------------------------------------------------;
  498. ; This procedure prompts for a new disk drive letter, like A, B, ....    ;
  499. ;                                    ;
  500. ; Uses:        WRITE_PROMPT_LINE, WRITE_EDITOR_PROMPT, INIT_SEC_DISP    ;
  501. ;        WRITE_STRING, CHAR_TO_UPPER, READ_BYTE, QUIT_FILE_MODE    ;
  502. ; Reads:    DISK_PROMPT, FILE_FLAG, READING_MESSAGE            ;
  503. ; Writes:    DISK_DRIVE_NO, CURRENT_SECTOR_NO            ;
  504. ;-----------------------------------------------------------------------;
  505. CHANGE_DISK_DRIVE    PROC    NEAR
  506.     PUSH    AX
  507.     PUSH    DX
  508.  
  509. READ_DRIVE_LOOP:
  510.     LEA    DX,DISK_PROMPT        ;Display prompt for drive letter
  511.     CALL    WRITE_PROMPT_LINE
  512.     CALL    READ_BYTE        ;Get new disk-drive number
  513.     CMP    AH,1            ;Did it read a character?
  514.     JNE    DONT_CHANGE_DRIVE    ;No, don't change the drive number
  515.     CMP    AL,25            ;Yes, was it hex number <=25 decimal
  516.     JBE    CHANGE_DRIVE        ;Yes, change drive number
  517.  
  518.     CMP    AL,'0'            ;No, is it a single digit number
  519.     JB    READ_DRIVE_LOOP        ;Yes, convert to drive number
  520.     CMP    AL,'9'            ;Is it a digit?
  521.     JBE    IS_SINGLE_DIGIT        ;Yes, convert to drive number
  522.  
  523.     CALL    CHAR_TO_UPPER        ;Convert letter to upper-case
  524.     CMP    AL,'A'            ;Is this a legal drive letter?
  525.     JB    READ_DRIVE_LOOP        ;No, try again
  526.     CMP    AL,'Z'            ;Is this a legal drive letter?
  527.     JA    READ_DRIVE_LOOP        ;No, then try again
  528.  
  529. IS_DRIVE_LETTER:            ;Yes, then convert to drive number
  530.     SUB    AL,'A'            ;Convert Upper letter to drive number
  531.     JMP    CHANGE_DRIVE        ;Change the drive number
  532.  
  533. IS_SINGLE_DIGIT:
  534.     SUB    AL,'0'            ;Convert to drive number
  535.  
  536. CHANGE_DRIVE:
  537.     CALL    QUIT_FILE_MODE        ;Turn off file mode, if on
  538.     MOV    CURRENT_SECTOR_NO,0    ;And view sector 0 of new drive
  539. CHANGE_DRIVE_NOT_FILE:
  540.     MOV    DISK_DRIVE_NO,AL    ;Save the new drive number
  541.     LEA    DX,READING_MESSAGE    ;Provide some feedback while reading
  542.     CALL    WRITE_STRING        ;Display this string
  543.     CALL    INIT_SEC_DISP        ;And display the new sector
  544. DONT_CHANGE_DRIVE:
  545.     CALL    WRITE_EDITOR_PROMPT    ;Display the Edit prompt
  546.     POP    DX
  547.     POP    AX
  548.     RET
  549. CHANGE_DISK_DRIVE    ENDP
  550.  
  551.  
  552.     PUBLIC    READ_SECTOR_NUMBER
  553.     EXTRN    WRITE_PROMPT_LINE:NEAR, READ_DECIMAL:NEAR
  554.     EXTRN    WRITE_STRING:NEAR, INIT_SEC_DISP:NEAR
  555.     EXTRN    WRITE_EDITOR_PROMPT:NEAR
  556. DATA_SEG    SEGMENT    PUBLIC
  557.     EXTRN    SECTOR_PROMPT:BYTE
  558.     EXTRN    CURRENT_SECTOR_NO:WORD, FILE_FLAG:BYTE
  559. DATA_SEG    ENDS
  560. ;-----------------------------------------------------------------------;
  561. ; This procedure prompts for the number of a new sector to read.    ;
  562. ;                                    ;
  563. ; Uses:        WRITE_PROMPT_LINE, READ_DECIMAL, WRITE_STRING        ;
  564. ;        INIT_SEC_DISP, QUIT_FILE_MODE, WRITE_EDITOR_PROMPT    ;
  565. ; Reads:    SECTOR_PROMPT, READING_MESSAGE                ;
  566. ; Writes:    CURRENT_SECTOR_NO                    ;
  567. ;-----------------------------------------------------------------------;
  568. READ_SECTOR_NUMBER    PROC    NEAR
  569.     PUSH    AX
  570.     PUSH    DX
  571.     LEA    DX,SECTOR_PROMPT    ;Prompt for the sector number
  572.     CALL    WRITE_PROMPT_LINE
  573.     CALL    READ_DECIMAL        ;Read the new sector number into AX
  574.     JC    DONT_CHANGE_SECTOR    ;Error, so exit without changing
  575.     CALL    QUIT_FILE_MODE        ;Turn off file mode, if on
  576.     MOV    CURRENT_SECTOR_NO,AX    ;Save the new sector number
  577.     LEA    DX,READING_MESSAGE    ;Provide feedback while we read
  578.     CALL    WRITE_STRING
  579.     CALL    INIT_SEC_DISP        ;Display the new sector
  580. DONT_CHANGE_SECTOR:
  581.     CALL    WRITE_EDITOR_PROMPT    ;Display the Edit prompt
  582.     POP    DX
  583.     POP    AX
  584.     RET
  585. READ_SECTOR_NUMBER    ENDP
  586.  
  587.  
  588.     PUBLIC    OPEN_NEW_FILE
  589.     EXTRN    WRITE_STRING:NEAR, INIT_SEC_DISP:NEAR
  590.     EXTRN    WRITE_PROMPT_LINE:NEAR, READ_CHAR:NEAR
  591.     EXTRN    WRITE_EDITOR_PROMPT:NEAR
  592. DATA_SEG    SEGMENT PUBLIC
  593.     EXTRN    CURRENT_SECTOR_NO:WORD, FILE_FLAG:BYTE
  594. DATA_SEG    ENDS
  595. ;-----------------------------------------------------------------------;
  596. ; This procedure reads a file name, opens that file, and displays the    ;
  597. ; first sector.                                ;
  598. ;                                    ;
  599. ; If the open failed, puts you back to editing whatever you were    ;
  600. ; editing before.                            ;
  601. ;                                    ;
  602. ; NOTE: This procedure needs a lot of work.  If you were in file mode    ;
  603. ;    when you ask to open a new file, this procedure closes the old    ;
  604. ;    file, then tries to open the new file.  If there was an error    ;
  605. ;    reading the new file, or you just hit <Enter>, this procedure    ;
  606. ;    doesn't return to the file you were previously editing.        ;
  607. ;    instead, it returns to sector mode.  See if you can change    ;
  608. ;    this procedure so that it returns to editing the last file you    ;
  609. ;    were on if you were in file mode.                ;
  610. ;                                    ;
  611. ; Uses:        READ_FILE_NAME, OPEN_FILE, WRITE_STRING            ;
  612. ;        INIT_SEC_DISP, WRITE_IO_ERROR, WRITE_PROMPT_LINE    ;
  613. ;        READ_CHAR, WRITE_EDITOR_PROMPT, QUIT_FILE_MODE        ;
  614. ; Reads:    READING_MESSAGE, DISK_ERROR_FLAG, PRESS_KEY        ;
  615. ; Writes:    CURRENT_SECTOR_NO, FILE_FLAG, DISK_ERROR_FLAG        ;
  616. ;-----------------------------------------------------------------------;
  617. OPEN_NEW_FILE    PROC    NEAR
  618.     PUSH    AX
  619.     PUSH    DX
  620.     CALL    QUIT_FILE_MODE        ;Turn off old file mode, if on
  621.  
  622.     CALL    READ_FILE_NAME        ;First, read in the file name
  623.     OR    AX,AX            ;Did we read any characters?
  624.     JLE    DONE_OPEN_NEW_FILE    ;No, then return without change
  625.  
  626.     LEA    DX,READING_MESSAGE    ;Yes, Provide feedback while we read
  627.     CALL    WRITE_STRING
  628.     CALL    OPEN_FILE        ;Try to open this file
  629.     CMP    DISK_ERROR_FLAG,1    ;Was there an I/O error?
  630.     JE    OPEN_NEW_FILE_ERROR    ;Yes, then report it.
  631.  
  632. SET_FILE_MODE:
  633.     MOV    FILE_FLAG,1        ;No, signal now in file mode
  634.     MOV    CURRENT_SECTOR_NO,0    ;Start at beginning of file
  635.  
  636. DONE_OPEN_NEW_FILE:
  637.     CALL    INIT_SEC_DISP        ;Display this new sector
  638.     CALL    WRITE_IO_ERROR        ;Display or clear error message
  639.     CALL    WRITE_EDITOR_PROMPT    ;Display the Edit prompt
  640.     POP    DX
  641.     POP    AX
  642.     RET
  643.  
  644. ;-----------------------------------------------;
  645. ; Here we report the error, then pause until    ;
  646. ; you press a key before returning to the    ;
  647. ; previous mode and sector that you were    ;
  648. ; viewing.                    ;
  649. ;-----------------------------------------------;
  650. OPEN_NEW_FILE_ERROR:
  651.     CALL    WRITE_IO_ERROR        ;Display the error message
  652.     LEA    DX,PRESS_KEY        ;Display prompt message
  653.     CALL    WRITE_PROMPT_LINE    ;Display this prompt
  654.     CALL    READ_CHAR        ;Read one character
  655.     JMP    DONE_OPEN_NEW_FILE    ;We're all done now
  656. OPEN_NEW_FILE    ENDP
  657.  
  658.  
  659.     PUBLIC    READ_FILE_NAME
  660.     EXTRN    WRITE_PROMPT_LINE:NEAR, READ_STRING:NEAR
  661. DATA_SEG    SEGMENT PUBLIC
  662.     EXTRN    FILE_NAME_PROMPT:BYTE
  663.     EXTRN    FILE_NAME_STRING:BYTE
  664.     EXTRN    LENGTH_READ:BYTE
  665.     EXTRN    FILE_NAME:BYTE
  666. DATA_SEG    ENDS
  667. ;-----------------------------------------------------------------------;
  668. ; This procedure prompts for a file name, then reads in the file name.    ;
  669. ; We've written this as a separate procedure only to make the code more    ;
  670. ; readable.                                ;
  671. ;                                    ;
  672. ; Returns:    AX    Number of characters read.            ;
  673. ;            -1 if you pressed a special key            ;
  674. ;                                    ;
  675. ; Uses:        WRITE_PROMPT_LINE, READ_STRING                ;
  676. ; Reads:    FILE_NAME_PROMPT, FILE_NAME_STRING, LENGTH_READ        ;
  677. ; Writes:    FILE_NAME                        ;
  678. ;-----------------------------------------------------------------------;
  679. READ_FILE_NAME    PROC    NEAR
  680.     PUSH    BX
  681.     PUSH    DX
  682.     LEA    DX,FILE_NAME_PROMPT    ;Display the "file name:"
  683.     CALL    WRITE_PROMPT_LINE    ; prompt
  684.     LEA    DX,FILE_NAME_STRING    ;Read in the file name
  685. READ_NAME_AGAIN:
  686.     CALL    READ_STRING
  687.     MOV    BL,LENGTH_READ        ;Get number of 
  688.     OR    BL,BL            ;Was this a function key?
  689.     JL    DONE_READ_FILE_NAME    ;Yes, then ignore it
  690.  
  691.     XOR    BH,BH            ;Clear the upper byte
  692.     MOV    FILE_NAME[BX],0        ;Convert string into ASCIIZ
  693. DONE_READ_FILE_NAME:
  694.     MOV    AL,BL            ;Return the length of the string
  695.     CBW                ;Extend sign into the upper byte
  696.     POP    DX
  697.     POP    BX
  698.     RET
  699. READ_FILE_NAME    ENDP
  700.  
  701.  
  702.     PUBLIC    OPEN_FILE
  703. DATA_SEG    SEGMENT PUBLIC
  704.     EXTRN    FILE_HANDLE:WORD
  705. DATA_SEG    ENDS
  706. ;-----------------------------------------------------------------------;
  707. ; This procedure is used by OPEN_NEW_FILE to open a file for reading    ;
  708. ; and writing.                                ;
  709. ;                                    ;
  710. ; Reads:    FILE_NAME                        ;
  711. ; Writes:    DISK_ERROR_FLAG, DISK_ERROR_CODE, FILE_HANDLE        ;
  712. ;-----------------------------------------------------------------------;
  713. OPEN_FILE    PROC    NEAR
  714.     PUSH    AX
  715.     PUSH    DX
  716.     MOV    DISK_ERROR_FLAG,0    ;Clear the error condition
  717.     MOV    AX,3D02h        ;Open file for read/write
  718.     LEA    DX,FILE_NAME        ;Get address of the file name
  719.     INT    21h
  720.     JC    FILE_OPEN_ERROR        ;There was an error, report it
  721.     MOV    FILE_HANDLE,AX        ;Save this file handle
  722. DONE_OPEN_FILE:
  723.     POP    DX
  724.     POP    AX
  725.     RET
  726.  
  727. FILE_OPEN_ERROR:
  728.     CMP    AX,2            ;Is this a file-not-found message?
  729.     JNE    CHECK_ACCESS
  730.     MOV    AX,0Eh            ;Error code for file-not-found
  731.     JMP    DONE_FILE_ERROR
  732. CHECK_ACCESS:
  733.     MOV    AX,0Dh            ;General Error reading file message
  734. DONE_FILE_ERROR:
  735.     MOV    DISK_ERROR_FLAG,1    ;Set the error flag
  736.     MOV    DISK_ERROR_CODE,AL    ;Save the new error code
  737.     JMP    DONE_OPEN_FILE        ;We're all done, return.
  738. OPEN_FILE    ENDP
  739.  
  740.  
  741.     PUBLIC    QUIT_FILE_MODE
  742. DATA_SEG    SEGMENT PUBLIC
  743.     EXTRN    FILE_HANDLE:WORD
  744.     EXTRN    CURRENT_SECTOR_NO:WORD
  745. DATA_SEG    ENDS
  746. ;-----------------------------------------------------------------------;
  747. ; This procedure checks to see if we're in file mode, and if so, it    ;
  748. ; closes the file, then turns off file mode.                ;
  749. ;                                    ;
  750. ; Reads:    FILE_HANDLE                        ;
  751. ; Writes:    FILE_FLAG, CURRENT_SECTOR_NO, DISK_ERROR_FLAG        ;
  752. ;-----------------------------------------------------------------------;
  753. QUIT_FILE_MODE    PROC    NEAR
  754.     PUSH    AX
  755.     PUSH    BX
  756.     CMP    FILE_FLAG,1        ;Are we in file mode?
  757.     JNE    DONE_QUIT_FILE        ;No, then we're all done
  758.     MOV    AH,3Eh            ;Ask to close this file
  759.     MOV    BX,FILE_HANDLE        ;Get the file handle
  760.     INT    21h            ;Close this file
  761.     MOV    FILE_FLAG,0        ;Turn off file mode
  762.     MOV    CURRENT_SECTOR_NO,0    ;Move to start of disk
  763.     MOV    DISK_ERROR_FLAG,0    ;Ignore any error conditions
  764. DONE_QUIT_FILE:
  765.     POP    BX
  766.     POP    AX
  767.     RET
  768. QUIT_FILE_MODE    ENDP
  769.  
  770.  
  771.  
  772.     PUBLIC    READ_OFFSET_NUMBER
  773. DATA_SEG    SEGMENT PUBLIC
  774.     EXTRN    OFFSET_PROMPT:BYTE
  775.     EXTRN    FILE_FLAG:BYTE, CURRENT_SECTOR_NO:WORD
  776. DATA_SEG    ENDS
  777.     EXTRN    WRITE_PROMPT_LINE:NEAR, READ_DECIMAL:NEAR
  778.     EXTRN    WRITE_STRING:NEAR, INIT_SEC_DISP:NEAR
  779.     EXTRN    WRITE_EDITOR_PROMPT:NEAR
  780. ;-----------------------------------------------------------------------;
  781. ; This procedure reads in the sector offset within a file, then        ;
  782. ; displays the new sector.                        ;
  783. ;                                    ;
  784. ; Uses:        WRITE_PROMPT_LINE, READ_DECIMAL, WRITE_STRING        ;
  785. ;        INIT_SEC_DISP, WRITE_EDITOR_PROMPT            ;
  786. ; Reads:    FILE_FLAG, OFFSET_PROMPT, READING_MESSAGE        ;
  787. ; Writes:    CURRENT_SECTOR_NO                    ;
  788. ;-----------------------------------------------------------------------;
  789. READ_OFFSET_NUMBER    PROC    NEAR
  790.     PUSH    AX
  791.     PUSH    DX
  792.     CMP    FILE_FLAG,1        ;In file mode?
  793.     JNE    READ_OFFSET_NOT_FILE_MODE    ;No, then just ignore request
  794.     LEA    DX,OFFSET_PROMPT    ;Yes, display the offset prompt
  795.     CALL    WRITE_PROMPT_LINE
  796.     CALL    READ_DECIMAL        ;Read in the decimal number
  797.     JC    DONT_CHANGE_OFFSET    ;Error, so exit without changing
  798.     LEA    DX,READING_MESSAGE    ;Provide feedback while we read
  799.     CALL    WRITE_STRING
  800.     MOV    CURRENT_SECTOR_NO,AX    ;Save the new number
  801.     CALL    INIT_SEC_DISP        ;Draw the new display
  802. DONT_CHANGE_OFFSET:
  803. READ_OFFSET_NOT_FILE_MODE:
  804.     CALL    WRITE_EDITOR_PROMPT    ;Display the Edit prompt
  805.     POP    DX
  806.     POP    AX
  807.     RET
  808. READ_OFFSET_NUMBER    ENDP
  809.  
  810.  
  811.     PUBLIC    READ_FILE_SECTOR
  812. DATA_SEG    SEGMENT PUBLIC
  813.     EXTRN    FILE_HANDLE:WORD
  814.     EXTRN    SECTOR:BYTE
  815. DATA_SEG    ENDS
  816. ;-----------------------------------------------------------------------;
  817. ; This procedure reads a random sector from a file.  It also saves a    ;
  818. ; count of the number of bytes actually read so that the write function    ;
  819. ; won't increase the size of a file.                    ;
  820. ;                                    ;
  821. ; Uses:        SET_FILE_POINTER                    ;
  822. ; Reads:    FILE_HANDLE, DISK_ERROR_FLAG                ;
  823. ; Writes:    SECTOR, DISK_ERROR_FLAG, DISK_ERROR_CODE, BYTES_READ    ;
  824. ;-----------------------------------------------------------------------;
  825. READ_FILE_SECTOR    PROC    NEAR
  826.     PUSH    AX
  827.     PUSH    BX
  828.     PUSH    CX
  829.     PUSH    DX
  830.     CALL    SET_FILE_POINTER    ;Set to start of current sector
  831.     CMP    DISK_ERROR_FLAG,1    ;Was there an error?
  832.     JE    DONE_READ_FILE_SECTOR    ;Yes, then don't try to read sector
  833.  
  834.     MOV    AH,3Fh            ;Call for a read on this file
  835.     MOV    BX,FILE_HANDLE        ;Get the file handle
  836.     MOV    CX,512            ;Read one sector of 512 bytes
  837.     LEA    DX,SECTOR        ;Address of our sector buffer
  838.     INT    21h            ;Let DOS read this sector
  839.     MOV    BYTES_READ,AX        ;Save number of bytes we read
  840.  
  841.     OR    AX,AX            ;Did we read anything from file?
  842.     JZ    READ_PAST_END        ;No, we read past end of file, signal
  843.  
  844. DONE_READ_FILE_SECTOR:
  845.     POP    DX
  846.     POP    CX
  847.     POP    BX
  848.     POP    AX
  849.     RET
  850.  
  851. READ_PAST_END:
  852.     MOV    DISK_ERROR_FLAG,1    ;Signal that there was an error
  853.     MOV    DISK_ERROR_CODE,0Fh    ;Read-past-end error code
  854.     JMP    DONE_READ_FILE_SECTOR
  855. READ_FILE_SECTOR    ENDP
  856.  
  857.  
  858.     PUBLIC    SET_FILE_POINTER
  859. DATA_SEG    SEGMENT PUBLIC
  860.     EXTRN    CURRENT_SECTOR_NO:WORD
  861.     EXTRN    FILE_HANDLE:WORD
  862. DATA_SEG    ENDS
  863. ;-----------------------------------------------------------------------;
  864. ; This procedure sets the file pointer to the sector number.        ;
  865. ;                                    ;
  866. ; Reads:    CURRENT_SECTOR_NO, FILE_HANDLE                ;
  867. ;-----------------------------------------------------------------------;
  868. SET_FILE_POINTER    PROC    NEAR
  869.     PUSH    AX
  870.     PUSH    BX
  871.     PUSH    CX
  872.     PUSH    DX
  873.     MOV    AX,CURRENT_SECTOR_NO    ;Get sector number for sector to read
  874.     MOV    BX,512            ;Size of the sector
  875.     MUL    BX            ;DX:AX = Offset from start of file
  876.     MOV    CX,AX            ;DX:CX = Offset in bytes
  877.     XCHG    CX,DX            ;CX:DX now contains the offset
  878.  
  879.     MOV    AX,4200h        ;Move to this position in the file
  880.     MOV    BX,FILE_HANDLE        ;Get the file handle
  881.     INT    21h            ;Move the file pointer
  882.  
  883.     POP    DX
  884.     POP    CX
  885.     POP    BX
  886.     POP    AX
  887.     RET
  888. SET_FILE_POINTER    ENDP
  889.  
  890.  
  891.     PUBLIC    WRITE_FILE_SECTOR
  892. DATA_SEG    SEGMENT PUBLIC
  893.     EXTRN    FILE_HANDLE:WORD
  894. DATA_SEG    ENDS
  895. ;-----------------------------------------------------------------------;
  896. ; This procedure writes a single sector back to the file that you were    ;
  897. ; viewing.  Note, this can change the length of the file if you write    ;
  898. ; the last sector, and the file was not a multiple of 512 bytes.  In    ;
  899. ; such cases, this procedure will increase the file length to a        ;
  900. ; multiple of 512 bytes.                        ;
  901. ;                                    ;
  902. ; Uses:        SET_FILE_POINTER
  903. ; Reads:    DISK_ERROR_FLAG, FILE_HANDLE, BYTES_READ, SECTOR
  904. ;-----------------------------------------------------------------------;
  905. WRITE_FILE_SECTOR    PROC    NEAR
  906.     PUSH    AX
  907.     PUSH    BX
  908.     PUSH    CX
  909.     PUSH    DX
  910.  
  911.     CALL    SET_FILE_POINTER    ;Set to start of current sector
  912.     CMP    DISK_ERROR_FLAG,1    ;Was there an error?
  913.     JE    DONE_WRITE_FILE_SECTOR    ;Yes, then don't try to write sector
  914.  
  915.     MOV    AH,40h            ;Call for a write to this file
  916.     MOV    BX,FILE_HANDLE        ;Get the file handle
  917.     MOV    CX,BYTES_READ        ;Don't write more than we read
  918.     LEA    DX,SECTOR        ;Address of our sector buffer
  919.     INT    21h            ;Let DOS write this sector
  920.     CMP    DISK_ERROR_FLAG,1    ;Was there a disk error
  921.     JE    DONE_WRITE_FILE_SECTOR    ;Yes, then return
  922.  
  923.     MOV    AH,45h            ;Duplicate the file handle
  924.     INT    21h            ;AX == the new file handle
  925.     MOV    BX,AX            ;Put new file handle into AX
  926.     MOV    AH,3Eh            ;Close duplicate handle to update
  927.     INT    21h            ;The changes we just made
  928.  
  929. DONE_WRITE_FILE_SECTOR:
  930.     POP    DX
  931.     POP    CX
  932.     POP    BX
  933.     POP    AX
  934.     RET
  935. WRITE_FILE_SECTOR    ENDP
  936.  
  937.  
  938. CODE_SEG    ENDS
  939.  
  940.     END
  941.