home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / nor_asm / disk_io.asm < prev    next >
Assembly Source File  |  1989-08-14  |  33KB  |  987 lines

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