home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / asm_kit / flist.asm < prev    next >
Assembly Source File  |  1983-11-16  |  28KB  |  786 lines

  1.           NAME    FLIST
  2.           PAGE    60,132
  3.           TITLE    'FLIST - Alphabetically Sorted List of Diskette Files'
  4. ;
  5. ; References: 1     DOS 2.0 Manual
  6. ;          2     IBM Macro Assembler Manual
  7. ;
  8. DATA          SEGMENT    PARA      PUBLIC 'DATA'
  9. ;
  10. ; Extended File Control Block Area (see 1, pages E-10 through E-14 for a
  11. ; description of Standard and Extended File Control Blocks):
  12.   FCB_FLAG    DB          (0)         ;FCB extension flag
  13.   RES_AREA1   DB    5    DUP  (0)         ;Reserved space ???
  14.   FCB_ATTR    DB          (0)         ;1=read only, 2=hidden file,
  15. ; Standard FCB:                   4=system file (see 1, C.4)
  16.   FCB_DRIVE   DB          (0)         ;1=A, 2=B, etc.
  17.   FILE_NAME   DB          '????????'     ;Left-justfd, trailing blanks
  18.   FILE_EXT    DB          '???'          ;Left-justfd, trailing blanks
  19.   CUR_BLOCK   DW          (0)         ;Current block, starting at 0
  20.   REC_SIZE    DW          (0)         ;Initialized to 128 bytes
  21.   FILE_SIZE   DW    2    DUP  (0)         ;Least-significant word is 1st
  22.   LAST_UPDT   DW          (0)         ;Last update (see 1, E-12)
  23.   RES_AREA2   DW    5    DUP  (0)         ;Reserved space ???
  24.   REL_RECNO   DB          (0)         ;Cur. rel. rec. no. (0-127)
  25.   ACT_RECNO   DW    2    DUP  (0)         ;Actual rec. no. (see 1, E-12)
  26. ; End of Extended FCB Area
  27. ;
  28. ; Extended DOS Disk Transfer Area (see 1, D-22 for a description of the data
  29. ; transferred by INT 21H, AH=11, and pages C-3 through C-6 for a description of
  30. ; the DOS Disk Directory):
  31.   DTA_FLAG    DB          (0)         ;Extension flag from FCB_FLAG
  32.   RES_AREA3   DB    5    DUP  (0)         ;Reserved space ???
  33.   SRCH_ATTR   DB          (0)         ;Search attr. from FCB_ATTR
  34. ; Standard DTA:
  35.   DTA_DRIVE   DB          (0)         ;1=A, 2=B, etc.
  36.   DTA_FNAME   DB    8    DUP  (0)         ;First byte indicates status
  37.   DTA_FEXT    DB    3    DUP  (0)         ;Left-justfd, trailing blanks
  38.   DTA_ATTR    DB          (0)         ;File attribute (see FCB_ATTR)
  39.   RES_AREA4   DW    5    DUP  (0)         ;Reserved space ???
  40.   DTA_TIME    DW          (0)         ;Time of last update
  41.   DTA_DATE    DW          (0)         ;Date of last update
  42.   STRT_CLSTR  DW          (0)         ;First relative cluster number
  43.   DTA_FSIZE   DW    2    DUP  (0)         ;Least-significant word is 1st
  44. ; End of Extended DTA Area
  45. ;
  46. ; Disk Format Table, used to interpret first byte of the File Allocation Table:
  47.   DISK_FORMAT DB          (0)         ;Disk format. See 1, C-7
  48.   FAT_FLAG    DB          0FFH         ;2 sided, 8 sectors-per-track
  49.           DW          FORMAT_28
  50.           DB          0FEH         ;1 sided, 8 sectors-per-track
  51.           DW          FORMAT_18
  52.           DB          0FDH         ;2 sided, 9 sectors-per-track
  53.           DW          FORMAT_29
  54.           DB          0FCH         ;1 sided, 9 sectors-per-track
  55.           DW          FORMAT_19
  56.           DB          0F8H         ;Fixed disk
  57.           DW          FORMAT_FD
  58.           DB          0         ;unknown end of table
  59.           DW          FORMAT_??
  60. ; End of Disk Format Table
  61. ;
  62. ; Top Line Information Area:
  63.   TLINE_1     DB    'Sorted Directory for '
  64.   REQ_DRIVE   DB    '@'                      ;The drive for which the dir.
  65. ;                          list was requested. A=A, etc.
  66.   TLINE_2     DB    ' Drive Diskette   |   UNUSED SPACE = $'
  67.   TLINE_3     DB    '  bytes',0DH,0AH
  68.   TLINE_4     DB    'Current Date: '
  69.   CURMONTH    DW    '00'
  70.   TLINE_5     DB    '/'
  71.   CURDAY      DW    '00'
  72.   TLINE_6     DB    '/'
  73.   CURYEAR     DW    '00'
  74.   TLINE_7     DB    '    Time: '
  75.   CURHOUR     DW    '00'
  76.   TLINE_8     DB    ':'
  77.   CURMIN      DW    '00'
  78.   TLINE_9     DB    '   |   DISK FORMAT  =  $'
  79.   FORMAT_18   DB    '1 sided 8 sectored$'
  80.   FORMAT_28   DB    '2 sided 8 sectored$'
  81.   FORMAT_19   DB    '1 sided 9 sectored$'
  82.   FORMAT_29   DB    '2 sided 9 sectored$'
  83.   FORMAT_FD   DB    'fixed disk$'
  84.   FORMAT_??   DB    'unknown$'
  85.   COL_TITLES  DB    'Filename.Ext        Size      Date$'
  86. ;
  87. ; End of Top Line Information Area
  88. ;
  89.   SKIP_1      DW    0D0AH             ;Carriage return / line feed
  90.   CR_LF       DW    0D0AH             ;Carriage return / line feed
  91.   PRINT_END   DB    '$'                      ;Print string terminator
  92.   TAB_4       DB    '    $'
  93.   TAB_6       DB    '      $'
  94.   TAB_8       DB    '        $'
  95. ;
  96.   DEF_DRIVE   DB          (0)         ;Default drive: 0=A, 1=B, etc.
  97.   FILE_COUNT  DW          (0)         ;Number of files in the disk
  98. ;                          directory which conform to
  99. ;                          the user-specified parameter
  100.   FIRST_ENTRY DW          (0)         ;Points to the first entry in
  101. ;                         ;alpha-sorted DIR_LIST
  102.   MID_ENTRY   DW          (0)         ;Points to the entry half-way
  103. ;                          down the sorted DIR_LIST
  104.   LAST_ENTRY  DW          (0)         ;Points to the byte after the
  105. ;                          last entry in DIR_LIST
  106.   FREE_SPACE  DW    2    DUP  (0)         ;The unused or available space
  107. ;                          on the disk
  108.   DIR_LIST    DB          (0)         ;Area used to save file
  109. ;                          directory data which conform
  110. ;                          to the user-specified param.
  111. ;          The structure of each entry in
  112. ;          DIR_LIST is as follows:
  113. ;
  114. ;          link pointer         2 bytes (1 word)
  115. ;          filename             8 bytes
  116. ;          . separator         1 byte
  117. ;          file extension         3 bytes
  118. ;          date of last update    2 bytes (1 word)
  119. ;          file size in bytes     4 bytes (2 words)
  120. ;                    --------
  121. ;          size of each entry:   20 bytes
  122. ;
  123. DATA          ENDS
  124. ;
  125.           USER_PARMS     EQU  05CH
  126.           INT24_SEG      EQU  090H
  127.           INT24_OFF      EQU  092H
  128. ;
  129. CODE          SEGMENT    PARA      PUBLIC 'CODE'
  130. MAIN          PROC    FAR
  131.           ASSUME    CS:CODE, SS:STACK
  132. ;
  133. ; Standard Program Prologue:
  134. ;
  135.           PUSH    DS             ;Save PSP Segment Address
  136.           XOR    AX,AX             ;Zero out AX and push it to
  137.           PUSH    AX             ;save PSP Offset Address
  138. ;
  139. ; Establish Extra Segment Addressability:
  140. ;
  141.           MOV    AX,DATA          ;Point ES to Data Segment and
  142.           MOV    ES,AX             ;establish Extra Segment
  143.           ASSUME    ES:DATA          ;Addressability
  144. ;
  145.           CALL    GET_PARMS
  146. ;
  147. ; Establish Data Segment Addressability:
  148. ;
  149.           PUSH    ES             ;Point DS to ES, i.e. our Data
  150.           POP    DS             ;Segment, and establish Data
  151.           ASSUME    DS:DATA          ;Segment Addressability
  152. ;
  153. ;
  154.           CALL    SETUP_DRIVE
  155. ;
  156.           CALL    SETUP_FCB
  157. ;
  158.           CALL    GET_ENTRIES
  159. ;
  160.           CALL    SORT_ENTRIES
  161. ;
  162.           CALL    FIND_MIDDLE
  163. ;
  164.           CALL    GET_FAT_INFO
  165. ;
  166.           CALL    DISPLAY_TOP
  167. ;
  168.           CALL    LIST_ENTRIES
  169. ;
  170.           CALL    RESET_DRIVE
  171. ;
  172.           RET                 ;Return control to DOS
  173. ;
  174. ; Move user-specified parameters (if any) from the first formatted FCB area in
  175. ; the PSP into the Extended FCB Area in our Data Segment:
  176. ;
  177. GET_PARMS     PROC    NEAR
  178.           MOV    SI,USER_PARMS         ;1st parm offset in PSP
  179.           MOV    DI,OFFSET FCB_DRIVE     ;Offset within our FCB area
  180.           MOV    CX,1             ;Initialize count to 1
  181.           CMP    BYTE PTR[SI+01],' '      ;Second byte is blank if the
  182. ;                          user specified no parameters
  183.           JE    SHORT XFER_PARM      ;Jump if no parms specified
  184.           ADD    CX,11             ;Otherwise, let CX = 12
  185. XFER_PARM:
  186.           CLD                 ;Set 'forward' MOVSB operation
  187.           REP    MOVSB             ;Transfer parameters
  188.           RET
  189. GET_PARMS     ENDP
  190. ;
  191. SETUP_DRIVE   PROC    NEAR
  192. ;
  193. ; Find the default drive and save the default drive code in DEF_DRIVE:
  194. ;
  195.           MOV    AH,19H             ;See 1, D-26
  196.           INT    21H             ;Code is returned in AL:
  197.           MOV    DEF_DRIVE,AL         ;0=A, 1=B, etc.
  198. ;
  199. ; If the user did not specify a drive in his parameters, FCB_DRIVE is 0. This
  200. ; must be changed to reflect the default drive code stored in DEF_DRIVE:
  201. ;
  202.           MOV    DL,FCB_DRIVE         ;0=default, 1=A, 2=B, etc.
  203.           DEC    DL             ;-1=default, 0=A, 1=B, etc.
  204.           JNS    SHORT CHECK_DRIVE     ;If user specified a drive,
  205. ;                          value of DL is "not signed"
  206. ;                          (DL => 0) so jump, i.e. DON'T
  207. ;                          adjust the value of DEF_DRIVE
  208.           INC    AL             ;Otherwise, set FCB_DRIVE to
  209.           MOV    FCB_DRIVE,AL         ;DEF_DRIVE: 1=A, 2=B, etc.
  210.           JMP    END_OF_CHECK
  211. CHECK_DRIVE:
  212. ;
  213. ; Change the default drive to that specified in the user parameters.
  214. ; The drive specified by the user is not necessarily valid.
  215. ;
  216.           MOV    AH,0EH             ;Use DL value to set default
  217.           INT    21H             ;drive (0=A, 1=B, etc.)
  218.           INC    DL             ;Number of drives is returned
  219.           CMP    DL,AL             ;in AL (1=1 drive, etc.)
  220.           JNA    END_OF_CHECK
  221.           MOV    DL,DEF_DRIVE         ;The user specified an invalid
  222.           INC    DL             ;drive so set the FCB_DRIVE to
  223.           MOV    FCB_DRIVE,DL         ;the default drive
  224. END_OF_CHECK:
  225.           MOV    AL,FCB_DRIVE         ;Record the value of FCB_DRIVE
  226.           ADD    REQ_DRIVE,AL         ;as a letter (A=1, B=2, etc.)
  227.           RET
  228. SETUP_DRIVE   ENDP
  229. ;
  230. ; Initialize the Extended FCB Area in our Data Segment to indicate that it is
  231. ; an Extended FCB and that we want to retrieve ALL files (including read-only,
  232. ; hidden, and system files) from the disk directory:
  233. ;
  234. SETUP_FCB     PROC    NEAR
  235.           MOV    AL,0FFH
  236.           MOV    FCB_FLAG,AL         ;See 1, E-14
  237.           MOV    AL,00000111B         ;See 1, C-4,C-5, and D-22,D-23
  238.           MOV    FCB_ATTR,AL         ;See 1, E-14
  239.           RET
  240. SETUP_FCB     ENDP
  241. ;
  242. ; Move each entry in the disk directory which conforms to the user parameters
  243. ; into the DIR_LIST in our Data Area:
  244. ;
  245. GET_ENTRIES   PROC    NEAR
  246.           MOV    BX,OFFSET DIR_LIST     ;Initialize LAST_ENTRY to
  247.           MOV    LAST_ENTRY,BX         ;beginning of DIR_LIST area
  248. ;
  249.           MOV    DX,OFFSET DTA_FLAG     ;Point DS:DX, the Disk
  250. ;                          Transfer Address, to our DTA
  251. ;                          Area so that data transferred
  252. ;                          from the disk will appear in
  253. ;                          Data Seg rather than the PSP
  254.           MOV    AH,1AH             ;Set Disk Transfer Address
  255.           INT    21H             ;(DTA) to DS:DX (see 1, D-26)
  256. ;
  257.           MOV    DX,OFFSET FCB_FLAG     ;Point DS:DX to our unopened
  258.           MOV    AH,11H             ;FCB Area and go looking for
  259.           INT    21H             ;the first match-up. If no
  260. ;                          files match-up whatsoever,
  261. ;                          AL returns  with a value of
  262.           OR    AL,AL             ;FF. Otherwise, AL is zero.
  263.           JNZ    END_XFER         ;If no entry whatsoever, jump
  264. ;                          Otherwise:
  265. DIR_XFER:
  266.           MOV    SI,OFFSET DTA_FNAME     ;Point to transferred filename
  267.           MOV    DI,LAST_ENTRY         ;Point DI to next entry space
  268.           LEA    DI,[DI+02]         ;in our DIR_LIST. Leave 2
  269. ;                          bytes for the link pointer
  270.           MOV    CX,8             ;8 byte filename to move
  271.           CLD                 ;Set 'forward' MOVSB operation
  272.           REP    MOVSB             ;Transfer the filename from
  273. ;                          the DTA to the DIR_LIST
  274.           MOV    BYTE PTR [DI],'.'        ;Set filename.ext period
  275.           INC    DI
  276.           MOV    CX,3             ;3 byte file extension to move
  277.           REP    MOVSB             ;Transfer the file extension
  278.           MOV    SI,OFFSET DTA_DATE     ;Transfer the date the file
  279.           MOVSW                 ;was created or last updated
  280.           MOV    SI,OFFSET DTA_FSIZE     ;Transfer size of file (bytes)
  281.           MOVSW                 ;Least-significant part of the
  282.           MOVSW                 ;size is stored in 1st word
  283. ;
  284.           ADD    BX,20             ;Each entry in DIR_LIST uses
  285.           MOV    LAST_ENTRY,BX         ;20 bytes. Update LAST_ENTRY
  286.           INC    WORD PTR FILE_COUNT     ;1 more file in the list
  287. ;
  288.           MOV    DX,OFFSET FCB_FLAG     ;Reset DS:DX to the start of
  289.           MOV    AH,12H             ;our FCB Area and go looking
  290.           INT    21H             ;for the next match-up in the
  291. ;                          disk directory
  292.           OR    AL,AL             ;Any more match-ups?
  293.           JZ    DIR_XFER         ;If so, jump back baby
  294. END_XFER:
  295.           RET
  296. GET_ENTRIES   ENDP
  297. ;
  298. ; The following code uses a bubble sort to establish a linked list of entries
  299. ; in DIR_LIST. The link pointers are stored in the first word of each entry in
  300. ; DIR_LIST and the variable FIRST_ENTRY points to the first entry in the sorted
  301. ; list. The link pointer in this first entry points to the second entry, etc.
  302. ; The last entry in the sorted list has a link pointer value of zero.
  303. ;
  304. ; At the start of each pass in the bubble sort, DI is set to the first entry
  305. ; in the sub-list sorted so far and SI points to the DIR_LIST entry being
  306. ; added to the sorted sub-list.  During the pass, DI moves up the sorted sub-
  307. ; list and the filename beginning at [DI+02] is compared to the filename at
  308. ; [SI+02].  BX points to the previous value of DI.  When the correct location
  309. ; for the SI entry is found in the sorted sub-list (entry in BX < entry in SI
  310. ; < entry in DI), the link pointer in BX is set to the offset of the SI entry
  311. ; and the link pointer in SI is set to the offset of the DI entry.
  312. ; i.e., BX points to SI and SI points to DI.
  313. ; A value of DI = 0 indicates that we are at the top of the sorted sub-list.
  314. ;
  315. SORT_ENTRIES  PROC    NEAR
  316.           MOV    SI,OFFSET DIR_LIST     ;Initially, select the first
  317. ;                          entry in DIR_LIST for sort
  318.           CMP    SI,LAST_ENTRY         ;If no entries in DIR_LIST,
  319.           JE    SHORT      END_SORT     ;bypass the sort step
  320. NEW_PASS:
  321.           MOV    DI,OFFSET FIRST_ENTRY     ;Point DI to the first entry
  322. ;                          in the sorted sub-list of
  323. ;                          DIR_LIST entries
  324. NEXT_COMPARE:
  325.           MOV    BX,DI             ;Update DI, retaining previous
  326.           MOV    DI,[BX]          ;value of DI in BX
  327.           OR    DI,DI             ;Are we at the top of the
  328.           JZ    FIX_PTRS         ;sub-list? If so, jump
  329.           PUSH    SI
  330.           PUSH    DI
  331.           LEA    SI,[SI+02]         ;If not, compare the filenames
  332.           LEA    DI,[DI+02]         ;pointed to by SI and DI
  333.           MOV    CX,12             ;12 chars in "filename.ext"
  334.           CLD                 ;Set 'forward' CMPSB operation
  335.           REPE    CMPSB             ;Compare until different:
  336. ;                          (value in SI - value in DI)
  337. ;                          i.e. result is positive if
  338. ;                          SI entry > DI entry
  339.           POP    DI
  340.           POP    SI
  341.           JA    NEXT_COMPARE         ;If the entry in SI is alpha-
  342. ;                          betically greater than the
  343. ;                          entry in DI, try the next
  344. ;                          entry in the sorted sub-list
  345. FIX_PTRS:
  346.           MOV    [BX],SI          ;Point BX entry to SI entry
  347.           MOV    [SI],DI          ;Point SI entry to DI entry
  348.           ADD    SI,20             ;Point SI to next entry in
  349. ;                          DIR_LIST to be sorted
  350.           CMP    SI,LAST_ENTRY         ;Proceed with a new pass only
  351.           JB    NEW_PASS         ;if we are not at the end of
  352. ;                          DIR_LIST
  353. END_SORT:
  354.           RET
  355. SORT_ENTRIES  ENDP
  356. ;
  357. ; The screen display is going to list the files in two columns.  To do this we
  358. ; must know the file entry in DIR_LIST which is half-way down the list, as
  359. ; this will be displayed on the right-hand side of the screen against the first
  360. ; entry in the list which will be displayed on the left-hand side, and so on
  361. ; down the list.  So here goes:
  362. ;
  363. FIND_MIDDLE   PROC    NEAR
  364.           MOV    CX,FILE_COUNT
  365.           SAR    CX,1             ;CX = FILE_COUNT / 2
  366.           JZ    NO_RHS
  367.           ADC    CL,00             ;Add 0 to CL ???
  368.           MOV    BX,OFFSET FIRST_ENTRY
  369. NEXT_ENTRY:
  370.           MOV    BX,[BX]          ;Find the entry which is half-
  371.           LOOP    NEXT_ENTRY         ;way down the sorted DIR_LIST
  372.           MOV    AX,[BX]
  373.           MOV    MID_ENTRY,AX         ;Save the list mid-point
  374.           XOR    AX,AX
  375.           MOV    [BX],AX          ;Set the link pointer in the
  376. ;                          mid-point entry to zero
  377. NO_RHS:
  378.           RET
  379. FIND_MIDDLE   ENDP
  380. ;
  381. ; Read the File Allocation Table information. See 1, C-1, C-2, C-6 through C-9,
  382. ; and D-26.
  383. ;
  384. GET_FAT_INFO  PROC    NEAR
  385.           PUSH    DS             ;DS is destroyed by next
  386. ;                          DOS function call
  387.           MOV    AH,1BH             ;Get DOS File Allocation Table
  388.           INT    21H             ;information. See 1, A-12
  389. ;                     On return, DS:BX points to FAT i.d. byte
  390. ;                     AL = number of sectors per cluster
  391. ;                     CX = number of bytes per sector
  392. ;                     DX = number of clusters (allocation units)
  393.           POP    DS             ;Restore DS to Data Segment
  394.           XCHG    CX,DX             ;Swap values in CX and DX
  395.           XOR    AH,AH             ;Zero out AH
  396.           MUL    DX             ;Multiply the no. of sectors
  397. ;                          per cluster (AX) by the
  398. ;                          physical sector size (DX)
  399.           PUSH    AX             ;Save AX = number of bytes per
  400. ;                          cluster
  401.           PUSH    CX             ;Save number of clusters (for
  402. ;                          future use as loop counter)
  403.           MOV    AH,2             ;Read sectors into memory
  404.           MOV    AL,2             ;Read two sectors
  405.           MOV    BX,OFFSET DIR_LIST+800H  ;Point ES:BX to buffer address
  406. ;                          at 2K bytes above DIR_LIST
  407.           XOR    CH,CH             ;Read track zero
  408.           MOV    CL,2             ;Start reading at sector 2
  409.           XOR    DH,DH             ;Read side zero (head 0)
  410.           MOV    DL,FCB_DRIVE         ;1=A, 2=B, etc.
  411.           DEC    DL             ;0=A, 1=B, etc.
  412.           INT    13H             ;Diskette I/O BIOS interrupt
  413.           MOV    AL,DIR_LIST+800H     ;Store first byte of FAT in
  414.           MOV    DISK_FORMAT,AL         ;DISK_FORMAT.    See 1, C-7
  415.           POP    CX             ;Number of clusters on disk
  416.           XOR    AX,AX             ;AX is used to accumulate the
  417. ;                          number of clusters unused or
  418. ;                          available on the disk
  419.           MOV    SI,02             ;Point to the cluster which
  420. ;                          begins mapping of the data
  421. ;                          area on the disk (see 1, C-7)
  422. NEXT_CLUSTER:
  423.           MOV    DI,SI             ;DI = SI
  424.           SHR    DI,1             ;DI = SI/2
  425.           ADD    DI,SI             ;DI = 1.5 * SI, i.e. the byte
  426. ;                          offset from the beginning of
  427. ;                          the FAT corresponding to the
  428. ;                          cluster numbered SI
  429.           MOV    DI,[BX+DI]         ;The address of the FAT entry
  430.           TEST    SI,01             ;If SI is even (right-most
  431.           JZ    EVEN_CLUSTER         ;bit is 0), jump
  432.           SHR    DI,1             ;Keep the 12 high-order bits
  433.           SHR    DI,1             ;of DI.  This is the fastest
  434.           SHR    DI,1             ;way to shift right 4 times,
  435.           SHR    DI,1             ;dividing DI by 16 (8 clocks)
  436. EVEN_CLUSTER:                     ;See 1, C-8, C-9
  437.           AND    DI,0FFFH         ;Check 12 low-order bits for
  438.           JNZ    IN_USE             ;000 (unused space)
  439.           INC    AX             ;AX = number of clusters not
  440. ;                          in use on the disk
  441. IN_USE:
  442.           INC    SI             ;Point to the next cluster in
  443. ;                          the File Allocation Table
  444.           LOOP    NEXT_CLUSTER
  445.           POP    DX             ;DX = number of bytes per
  446. ;                          cluster
  447.           MUL    DX             ;AX = number of bytes not in
  448. ;                          use on the disk. DX is set to
  449. ;                          most-significant word of
  450. ;                          AX*DX result. See 2, 6-114
  451.           MOV    FREE_SPACE,AX         ;Save least-significant and
  452.           MOV    FREE_SPACE+02,DX     ;most-sig. words of FREE_SPACE
  453.           PUSH    DS             ;Save pointer to Data Seg
  454.           XOR    AX,AX
  455.           MOV    DS,AX             ;Point DS to interrupt vectors
  456.           MOV    SI,[DS:INT24_SEG]     ;Segment address for INT 24H
  457.           MOV    DI,[DS:INT24_OFF]     ;Offset address for INT 24H
  458.           PUSH    DS             ;Save interrupt vector DS
  459.           PUSH    CS
  460.           POP    DS             ;Point DS to Code Segment
  461.           MOV    DX,OFFSET INT_24H     ;Set interrupt vector for
  462.           MOV    AL,24H             ;INT 24H to point to service
  463.           MOV    AH,25H             ;routine in our Code Segment
  464.           INT    21H             ;See 1, D-28
  465.           POP    DS             ;Reset DS to interrupt vectors
  466.           MOV    AH,0DH             ;Disk reset - flushes all file
  467.           INT    21H             ;buffers. See 1, D-20
  468.           MOV    [DS:INT24_SEG],SI     ;Reset interrupt vector for
  469.           MOV    [DS:INT24_OFF],DI     ;INT 24H to original address
  470.           POP    DS             ;Restore DS to Data Segment
  471.           RET
  472. GET_FAT_INFO  ENDP
  473. ;
  474. ; Replacement for DOS interrupt 24H, used in PROC GET_FAT_INFO:
  475. ;
  476. INT_24H       PROC    NEAR
  477.           STI                 ;Set Interrupt Flag
  478.           XOR    AX,AX             ;Zero out value of AX
  479.           IRET                 ;Interrupt Return
  480. INT_24H       ENDP
  481. ;
  482. ; Display the title line, including the requested drive and the available space
  483. ; on the disk. The value in FREE_SPACE must be converted from a 4-byte binary
  484. ; number to a multi-byte ASCII unpacked number before it can be displayed !!
  485. ;
  486. DISPLAY_TOP   PROC    NEAR
  487.           MOV    DX,OFFSET CR_LF
  488.           MOV    AH,9             ;Print string at DX,
  489.           INT    21H             ;terminated by $ sign
  490. ;
  491. ; Print the title line, including the requested drive and the unused
  492. ; (available) space on the diskette.
  493. ;
  494.           MOV    DX,OFFSET TLINE_1     ;Display the first part of the
  495.           MOV    AH,9             ;display line (up to the no.
  496.           INT    21H             ;of bytes of free space)
  497.           MOV    SI,FREE_SPACE         ;Create an ASCII string of
  498.           MOV    DI,FREE_SPACE+02     ;decimal numbers equivalent to
  499.           CALL    BIN_TO_ASCII         ;the binary number stored in
  500. ;                          SI:DI, and display the string
  501.           MOV    AH,2AH             ;Get cur. date. Date returned
  502.           INT    21H             ;in CX:DX. See 1, D-31
  503.           MOV    AL,DH             ;Move month (1-12) into AL
  504.           AAM                 ;ASCII adjust for multiply
  505.           XCHG    AL,AH             ;Put least-sig. byte first
  506.           OR    CURMONTH,AX         ;Store month in display line
  507.           MOV    AL,DL             ;Move day (1-31) into AL
  508.           AAM
  509.           XCHG    AL,AH
  510.           OR    CURDAY,AX         ;Store day in display line
  511.           MOV    AX,CX             ;Move year (1980-2099) into AL
  512.           SUB    AX,1900          ;Convert to (80-199)
  513.           AAM
  514.           XCHG    AL,AH
  515.           OR    CURYEAR,AX         ;Store year in display line
  516.           MOV    AH,2CH             ;Get cur. time. Time returned
  517.           INT    21H             ;in CX:DX. See 1, D-31
  518.           MOV    AL,CH             ;Move hours (0-23) into AL
  519.           AAM
  520.           XCHG    AL,AH
  521.           OR    CURHOUR,AX         ;Store hours in display line
  522.           MOV    AL,CL             ;Move minutes (0-59) into AL
  523.           AAM
  524.           XCHG    AL,AH
  525.           OR    CURMIN,AX         ;Store minutes in display line
  526. ;
  527.           MOV    DX,OFFSET TLINE_3     ;Display some more of the
  528.           MOV    AH,9             ;title line
  529.           INT    21H
  530. ;
  531. ; Determine the disk format and display the appropriate message:
  532. ;
  533.           MOV    BL,DISK_FORMAT
  534.           MOV    SI,OFFSET FAT_FLAG
  535.           CLD                 ;Set 'forward' LODSB operation
  536. NEXT_FORMAT:
  537.           LODSB                 ;Load byte addressed by SI
  538. ;                          into AL and increase SI
  539.           OR    AL,AL             ;If zero, we didn't match up
  540. ;                          any valid format type
  541.           JZ    SHORT DISP_FORMAT
  542.           CMP    AL,BL             ;Check byte from table against
  543. ;                          first byte from FAT
  544.           JZ    SHORT DISP_FORMAT
  545.           ADD    SI,02             ;Skip past the improper msg.
  546.           JMP    NEXT_FORMAT         ;Check for next format type
  547. DISP_FORMAT:
  548.           LODSW                 ;Load word addressed by SI
  549. ;                          into AX and increase SI, i.e.
  550.           MOV    DX,AX             ;Pick up message address,
  551.           MOV    AH,9             ;store address in DX, and
  552.           INT    21H             ;display the message
  553.           MOV    DX,OFFSET CR_LF      ;Carriage return, line feed
  554.           MOV    AH,9
  555.           INT    21H
  556. ; Display the column titles on the left-half of the screen and, if
  557. ; appropriate, also display them on the right-half of the screen
  558. ;
  559.           MOV    DX,OFFSET COL_TITLES
  560.           MOV    AH,9
  561.           INT    21H
  562.           CMP    WORD PTR  MID_ENTRY,0     ;Are there any entries for the
  563.           JZ    LINE_FEED         ;right-half of the screen?
  564.           MOV    DX,OFFSET TAB_8
  565.           MOV    AH,9
  566.           INT    21H
  567.           MOV    DX,OFFSET COL_TITLES
  568.           MOV    AH,9
  569.           INT    21H
  570. LINE_FEED:
  571.           MOV    DX,OFFSET SKIP_1
  572.           MOV    AH,9
  573.           INT    21H
  574.           RET
  575. DISPLAY_TOP   ENDP
  576. ;
  577. ; Display the lines containing the filenames, their sizes, and dates of last
  578. ; update. File sizes are stored as 4-byte binary numbers. The least-significant
  579. ; part of the number is in the first 2 bytes.
  580. ;
  581. LIST_ENTRIES  PROC    NEAR
  582. NEXT_LINE:
  583.           MOV    BX,FIRST_ENTRY         ;Point BX to the LHS entry to
  584.           OR    BX,BX             ;be displayed
  585.           JZ    END_OF_LIST
  586.           MOV    AX,[BX]          ;Adjust FIRST_ENTRY so that it
  587.           MOV    FIRST_ENTRY,AX         ;points to the following entry
  588. ;                          to be displayed on the LHS
  589.           CALL    DISPLAY_ENTRY
  590.           MOV    BX,MID_ENTRY         ;Point BX to the RHS entry to
  591.           OR    BX,BX             ;be displayed
  592.           JZ    END_OF_LINE
  593.           MOV    DX,OFFSET TAB_6      ;Leave 6 spaces down the
  594.           MOV    AH,9             ;middle of the screen,
  595.           INT    21H             ;separating LHS and RHS.
  596.           MOV    AX,[BX]          ;Adjust MID_ENTRY so that it
  597.           MOV    MID_ENTRY,AX         ;points to the following entry
  598. ;                         ;to be displayed on the RHS
  599.           CALL    DISPLAY_ENTRY
  600. END_OF_LINE:
  601.           MOV    DX,OFFSET CR_LF
  602.           MOV    AH,9
  603.           INT    21H
  604.           JMP    NEXT_LINE
  605. END_OF_LIST:
  606.           RET
  607. LIST_ENTRIES  ENDP
  608. ;
  609. ; Reset the default drive to its original status, as saved in DEF_DRIVE:
  610. ;
  611. RESET_DRIVE   PROC    NEAR
  612.           MOV    DL,DEF_DRIVE         ;Reset the default drive to
  613.           MOV    AH,0EH             ;the value stored in DEF_DRIVE
  614.           INT    21H
  615.           RET
  616. RESET_DRIVE   ENDP
  617. ;
  618. ; Display the filename, extension, size, and date of last update for the file
  619. ; in DIR_LIST pointed to by BX.
  620. ;
  621. DISPLAY_ENTRY PROC    NEAR
  622.           MOV    CX,12
  623.           XOR    DI,DI
  624. NEXT_CHAR:
  625.           MOV    DL,[BX+DI+02]         ;Display the filename, period
  626.           MOV    AH,02             ;separator, and file extension
  627.           INT    21H             ;(12 bytes), 1 byte at a time
  628.           INC    DI             ;Point to next character
  629.           LOOP    NEXT_CHAR         ;Loop controlled by CX
  630.           PUSH    BX
  631.           MOV    SI,[BX+16]         ;SI = least-significant word &
  632.           MOV    DI,[BX+18]         ;DI = most-significant word of
  633. ;                          binary number to be unpacked
  634.           CALL    BIN_TO_ASCII
  635.           POP    BX
  636.           MOV    DX,OFFSET TAB_4      ;Leave 4 spaces between the
  637.           MOV    AH,9             ;file size and the date of
  638.           INT    21H             ;last update
  639.           MOV    AX,[BX+14]         ;AX = the date of last update
  640.           CALL    DISPLAY_DATE
  641.           RET
  642. DISPLAY_ENTRY ENDP
  643. ;
  644. ; Interpret AX as a date and display it on the screen as an 8 character string:
  645. ;                (MM/DD/YY)
  646. ;
  647. DISPLAY_DATE  PROC    NEAR
  648.           OR    AX,AX
  649.           JNZ    REAL_DATE
  650.           MOV    DX,OFFSET TAB_8      ;Word at AX is all-zero so
  651.           MOV    AH,9             ;display 8 blanks instead of
  652.           INT    21H             ;a real date value
  653.           RET
  654. REAL_DATE:
  655.           PUSH    AX             ;Save date value stored in AX
  656.           AND    AX,0000000111100000B     ;Extract the month value from
  657.           MOV    CL,5             ;the date. See 1, C-5
  658.           SHR    AX,CL             ;Get rid of 5 least-sig. bits
  659.           CALL    DISPLAY_CHARS
  660.           MOV    DL,'/'                   ;Display the slash separator
  661.           MOV    AH,2             ;between the month and day
  662.           INT    21H             ;of last update
  663.           POP    AX             ;Restore date value to AX
  664.           PUSH    AX             ;and save it again
  665.           AND    AX,0000000000011111B     ;Extract the day value from
  666.           CALL    DISPLAY_CHARS         ;the date. No shift necessary
  667.           MOV    DL,'/'
  668.           MOV    AH,2             ;Slash is between day and year
  669.           INT    21H             ; of last update
  670.           POP    AX
  671.           AND    AX,1111111000000000B     ;Extract the year value from
  672.           MOV    CL,9             ;the date.  Get rid of the 9
  673.           SHR    AX,CL             ;least-significant bits in AX
  674.           ADD    AX,80             ;Zero value corresponds to
  675.           CALL    DISPLAY_CHARS         ;1980.  See 1, C-5
  676.           RET
  677. DISPLAY_DATE  ENDP
  678. ;
  679. ; Convert the binary number stored in AX to a decimal number and display it as
  680. ; 2 digits.
  681. ;
  682. DISPLAY_CHARS PROC NEAR
  683.           AAM
  684.           OR    AX,3030H         ;30H = 48 = ASCII value of 0
  685.           PUSH    AX
  686.           MOV    DL,AH             ;Display first digit of date
  687.           MOV    AH,2             ;field
  688.           INT    21H
  689.           POP    AX
  690.           MOV    DL,AL             ;Display second digit of date
  691.           MOV    AH,2             ;field
  692.           INT    21H
  693.           RET
  694. DISPLAY_CHARS ENDP
  695. ;
  696. ; Convert the 2-word binary number stored in SI:DI (where SI contains the
  697. ; least-significant part of the binary number and DI contains the
  698. ; most-significant part) into a multi-byte string containing the ASCII
  699. ; representation of the corresponding decimal number, and display the ASCII
  700. ; string on the screen at the current cursor location.
  701. ;
  702. BIN_TO_ASCII  PROC    NEAR
  703.           XOR    AX,AX
  704.           MOV    BX,AX
  705.           MOV    BP,AX
  706.           MOV    CX,32             ;32 bits to convert
  707. NEXT_BIT:
  708.           SHL    SI,1
  709.           RCL    DI,1
  710.           XCHG    AX,BP
  711.           CALL    BTOA_SUBR4
  712.           XCHG    AX,BP
  713.           XCHG    AX,BX
  714.           CALL    BTOA_SUBR4
  715.           XCHG    AX,BX
  716.           ADC    AL,0
  717.           LOOP    NEXT_BIT
  718.           MOV    CX,1B10H
  719.           CALL    BTOA_SUBR1
  720.           MOV    AX,BX
  721.           CALL    BTOA_SUBR1
  722.           MOV    AX,BP
  723.           CALL    BTOA_SUBR1
  724.           RET
  725. BIN_TO_ASCII  ENDP
  726. ;
  727. ;
  728. ;
  729. BTOA_SUBR1    PROC    NEAR
  730.           PUSH    AX
  731.           MOV    DL,AH
  732.           CALL    BTOA_SUBR2
  733.           POP    DX
  734.           CALL    BTOA_SUBR2
  735.           RET
  736. BTOA_SUBR1    ENDP
  737. ;
  738. ;
  739. ;
  740. BTOA_SUBR2    PROC    NEAR
  741.           MOV    DH,DL
  742.           SHR    DL,1
  743.           SHR    DL,1
  744.           SHR    DL,1
  745.           SHR    DL,1
  746.           CALL    BTOA_SUBR3
  747.           MOV    DL,DH
  748.           CALL    BTOA_SUBR3
  749.           RET
  750. BTOA_SUBR2    ENDP
  751. ;
  752. ;
  753. ;
  754. BTOA_SUBR3    PROC    NEAR
  755.           AND    DL,0FH
  756.           JZ    SHORT      TARGET
  757.           MOV    CL,0
  758. TARGET:
  759.           DEC    CH
  760.           AND    CL,CH
  761.           OR    DL,48             ;48 = ASCII value of zero
  762.           SUB    DL,CL             ;Display the character in DX
  763.           MOV    AH,2             ; on the screen
  764.           INT    21H
  765.           RET
  766. BTOA_SUBR3    ENDP
  767. ;
  768. ;
  769. ;
  770. BTOA_SUBR4    PROC    NEAR
  771.           ADC    AL,AL
  772.           DAA
  773.           XCHG    AL,AH
  774.           ADC    AL,AL
  775.           DAA
  776.           XCHG    AL,AH
  777.           RET
  778. BTOA_SUBR4    ENDP
  779. MAIN          ENDP
  780. CODE          ENDS
  781. ;
  782. STACK          SEGMENT    PARA      STACK 'CODE'
  783.           DB    128  DUP  (0)         ;128 Byte Stack Space
  784. STACK          ENDS
  785.           END    MAIN
  786.