home *** CD-ROM | disk | FTP | other *** search
- NAME FLIST
- PAGE 60,132
- TITLE 'FLIST - Alphabetically Sorted List of Diskette Files'
- ;
- ; References: 1 DOS 2.0 Manual
- ; 2 IBM Macro Assembler Manual
- ;
- DATA SEGMENT PARA PUBLIC 'DATA'
- ;
- ; Extended File Control Block Area (see 1, pages E-10 through E-14 for a
- ; description of Standard and Extended File Control Blocks):
- FCB_FLAG DB (0) ;FCB extension flag
- RES_AREA1 DB 5 DUP (0) ;Reserved space ???
- FCB_ATTR DB (0) ;1=read only, 2=hidden file,
- ; Standard FCB: 4=system file (see 1, C.4)
- FCB_DRIVE DB (0) ;1=A, 2=B, etc.
- FILE_NAME DB '????????' ;Left-justfd, trailing blanks
- FILE_EXT DB '???' ;Left-justfd, trailing blanks
- CUR_BLOCK DW (0) ;Current block, starting at 0
- REC_SIZE DW (0) ;Initialized to 128 bytes
- FILE_SIZE DW 2 DUP (0) ;Least-significant word is 1st
- LAST_UPDT DW (0) ;Last update (see 1, E-12)
- RES_AREA2 DW 5 DUP (0) ;Reserved space ???
- REL_RECNO DB (0) ;Cur. rel. rec. no. (0-127)
- ACT_RECNO DW 2 DUP (0) ;Actual rec. no. (see 1, E-12)
- ; End of Extended FCB Area
- ;
- ; Extended DOS Disk Transfer Area (see 1, D-22 for a description of the data
- ; transferred by INT 21H, AH=11, and pages C-3 through C-6 for a description of
- ; the DOS Disk Directory):
- DTA_FLAG DB (0) ;Extension flag from FCB_FLAG
- RES_AREA3 DB 5 DUP (0) ;Reserved space ???
- SRCH_ATTR DB (0) ;Search attr. from FCB_ATTR
- ; Standard DTA:
- DTA_DRIVE DB (0) ;1=A, 2=B, etc.
- DTA_FNAME DB 8 DUP (0) ;First byte indicates status
- DTA_FEXT DB 3 DUP (0) ;Left-justfd, trailing blanks
- DTA_ATTR DB (0) ;File attribute (see FCB_ATTR)
- RES_AREA4 DW 5 DUP (0) ;Reserved space ???
- DTA_TIME DW (0) ;Time of last update
- DTA_DATE DW (0) ;Date of last update
- STRT_CLSTR DW (0) ;First relative cluster number
- DTA_FSIZE DW 2 DUP (0) ;Least-significant word is 1st
- ; End of Extended DTA Area
- ;
- ; Disk Format Table, used to interpret first byte of the File Allocation Table:
- DISK_FORMAT DB (0) ;Disk format. See 1, C-7
- FAT_FLAG DB 0FFH ;2 sided, 8 sectors-per-track
- DW FORMAT_28
- DB 0FEH ;1 sided, 8 sectors-per-track
- DW FORMAT_18
- DB 0FDH ;2 sided, 9 sectors-per-track
- DW FORMAT_29
- DB 0FCH ;1 sided, 9 sectors-per-track
- DW FORMAT_19
- DB 0F8H ;Fixed disk
- DW FORMAT_FD
- DB 0 ;unknown end of table
- DW FORMAT_??
- ; End of Disk Format Table
- ;
- ; Top Line Information Area:
- TLINE_1 DB 'Sorted Directory for '
- REQ_DRIVE DB '@' ;The drive for which the dir.
- ; list was requested. A=A, etc.
- TLINE_2 DB ' Drive Diskette | UNUSED SPACE = $'
- TLINE_3 DB ' bytes',0DH,0AH
- TLINE_4 DB 'Current Date: '
- CURMONTH DW '00'
- TLINE_5 DB '/'
- CURDAY DW '00'
- TLINE_6 DB '/'
- CURYEAR DW '00'
- TLINE_7 DB ' Time: '
- CURHOUR DW '00'
- TLINE_8 DB ':'
- CURMIN DW '00'
- TLINE_9 DB ' | DISK FORMAT = $'
- FORMAT_18 DB '1 sided 8 sectored$'
- FORMAT_28 DB '2 sided 8 sectored$'
- FORMAT_19 DB '1 sided 9 sectored$'
- FORMAT_29 DB '2 sided 9 sectored$'
- FORMAT_FD DB 'fixed disk$'
- FORMAT_?? DB 'unknown$'
- COL_TITLES DB 'Filename.Ext Size Date$'
- ;
- ; End of Top Line Information Area
- ;
- SKIP_1 DW 0D0AH ;Carriage return / line feed
- CR_LF DW 0D0AH ;Carriage return / line feed
- PRINT_END DB '$' ;Print string terminator
- TAB_4 DB ' $'
- TAB_6 DB ' $'
- TAB_8 DB ' $'
- ;
- DEF_DRIVE DB (0) ;Default drive: 0=A, 1=B, etc.
- FILE_COUNT DW (0) ;Number of files in the disk
- ; directory which conform to
- ; the user-specified parameter
- FIRST_ENTRY DW (0) ;Points to the first entry in
- ; ;alpha-sorted DIR_LIST
- MID_ENTRY DW (0) ;Points to the entry half-way
- ; down the sorted DIR_LIST
- LAST_ENTRY DW (0) ;Points to the byte after the
- ; last entry in DIR_LIST
- FREE_SPACE DW 2 DUP (0) ;The unused or available space
- ; on the disk
- DIR_LIST DB (0) ;Area used to save file
- ; directory data which conform
- ; to the user-specified param.
- ; The structure of each entry in
- ; DIR_LIST is as follows:
- ;
- ; link pointer 2 bytes (1 word)
- ; filename 8 bytes
- ; . separator 1 byte
- ; file extension 3 bytes
- ; date of last update 2 bytes (1 word)
- ; file size in bytes 4 bytes (2 words)
- ; --------
- ; size of each entry: 20 bytes
- ;
- DATA ENDS
- ;
- USER_PARMS EQU 05CH
- INT24_SEG EQU 090H
- INT24_OFF EQU 092H
- ;
- CODE SEGMENT PARA PUBLIC 'CODE'
- MAIN PROC FAR
- ASSUME CS:CODE, SS:STACK
- ;
- ; Standard Program Prologue:
- ;
- PUSH DS ;Save PSP Segment Address
- XOR AX,AX ;Zero out AX and push it to
- PUSH AX ;save PSP Offset Address
- ;
- ; Establish Extra Segment Addressability:
- ;
- MOV AX,DATA ;Point ES to Data Segment and
- MOV ES,AX ;establish Extra Segment
- ASSUME ES:DATA ;Addressability
- ;
- CALL GET_PARMS
- ;
- ; Establish Data Segment Addressability:
- ;
- PUSH ES ;Point DS to ES, i.e. our Data
- POP DS ;Segment, and establish Data
- ASSUME DS:DATA ;Segment Addressability
- ;
- ;
- CALL SETUP_DRIVE
- ;
- CALL SETUP_FCB
- ;
- CALL GET_ENTRIES
- ;
- CALL SORT_ENTRIES
- ;
- CALL FIND_MIDDLE
- ;
- CALL GET_FAT_INFO
- ;
- CALL DISPLAY_TOP
- ;
- CALL LIST_ENTRIES
- ;
- CALL RESET_DRIVE
- ;
- RET ;Return control to DOS
- ;
- ; Move user-specified parameters (if any) from the first formatted FCB area in
- ; the PSP into the Extended FCB Area in our Data Segment:
- ;
- GET_PARMS PROC NEAR
- MOV SI,USER_PARMS ;1st parm offset in PSP
- MOV DI,OFFSET FCB_DRIVE ;Offset within our FCB area
- MOV CX,1 ;Initialize count to 1
- CMP BYTE PTR[SI+01],' ' ;Second byte is blank if the
- ; user specified no parameters
- JE SHORT XFER_PARM ;Jump if no parms specified
- ADD CX,11 ;Otherwise, let CX = 12
- XFER_PARM:
- CLD ;Set 'forward' MOVSB operation
- REP MOVSB ;Transfer parameters
- RET
- GET_PARMS ENDP
- ;
- SETUP_DRIVE PROC NEAR
- ;
- ; Find the default drive and save the default drive code in DEF_DRIVE:
- ;
- MOV AH,19H ;See 1, D-26
- INT 21H ;Code is returned in AL:
- MOV DEF_DRIVE,AL ;0=A, 1=B, etc.
- ;
- ; If the user did not specify a drive in his parameters, FCB_DRIVE is 0. This
- ; must be changed to reflect the default drive code stored in DEF_DRIVE:
- ;
- MOV DL,FCB_DRIVE ;0=default, 1=A, 2=B, etc.
- DEC DL ;-1=default, 0=A, 1=B, etc.
- JNS SHORT CHECK_DRIVE ;If user specified a drive,
- ; value of DL is "not signed"
- ; (DL => 0) so jump, i.e. DON'T
- ; adjust the value of DEF_DRIVE
- INC AL ;Otherwise, set FCB_DRIVE to
- MOV FCB_DRIVE,AL ;DEF_DRIVE: 1=A, 2=B, etc.
- JMP END_OF_CHECK
- CHECK_DRIVE:
- ;
- ; Change the default drive to that specified in the user parameters.
- ; The drive specified by the user is not necessarily valid.
- ;
- MOV AH,0EH ;Use DL value to set default
- INT 21H ;drive (0=A, 1=B, etc.)
- INC DL ;Number of drives is returned
- CMP DL,AL ;in AL (1=1 drive, etc.)
- JNA END_OF_CHECK
- MOV DL,DEF_DRIVE ;The user specified an invalid
- INC DL ;drive so set the FCB_DRIVE to
- MOV FCB_DRIVE,DL ;the default drive
- END_OF_CHECK:
- MOV AL,FCB_DRIVE ;Record the value of FCB_DRIVE
- ADD REQ_DRIVE,AL ;as a letter (A=1, B=2, etc.)
- RET
- SETUP_DRIVE ENDP
- ;
- ; Initialize the Extended FCB Area in our Data Segment to indicate that it is
- ; an Extended FCB and that we want to retrieve ALL files (including read-only,
- ; hidden, and system files) from the disk directory:
- ;
- SETUP_FCB PROC NEAR
- MOV AL,0FFH
- MOV FCB_FLAG,AL ;See 1, E-14
- MOV AL,00000111B ;See 1, C-4,C-5, and D-22,D-23
- MOV FCB_ATTR,AL ;See 1, E-14
- RET
- SETUP_FCB ENDP
- ;
- ; Move each entry in the disk directory which conforms to the user parameters
- ; into the DIR_LIST in our Data Area:
- ;
- GET_ENTRIES PROC NEAR
- MOV BX,OFFSET DIR_LIST ;Initialize LAST_ENTRY to
- MOV LAST_ENTRY,BX ;beginning of DIR_LIST area
- ;
- MOV DX,OFFSET DTA_FLAG ;Point DS:DX, the Disk
- ; Transfer Address, to our DTA
- ; Area so that data transferred
- ; from the disk will appear in
- ; Data Seg rather than the PSP
- MOV AH,1AH ;Set Disk Transfer Address
- INT 21H ;(DTA) to DS:DX (see 1, D-26)
- ;
- MOV DX,OFFSET FCB_FLAG ;Point DS:DX to our unopened
- MOV AH,11H ;FCB Area and go looking for
- INT 21H ;the first match-up. If no
- ; files match-up whatsoever,
- ; AL returns with a value of
- OR AL,AL ;FF. Otherwise, AL is zero.
- JNZ END_XFER ;If no entry whatsoever, jump
- ; Otherwise:
- DIR_XFER:
- MOV SI,OFFSET DTA_FNAME ;Point to transferred filename
- MOV DI,LAST_ENTRY ;Point DI to next entry space
- LEA DI,[DI+02] ;in our DIR_LIST. Leave 2
- ; bytes for the link pointer
- MOV CX,8 ;8 byte filename to move
- CLD ;Set 'forward' MOVSB operation
- REP MOVSB ;Transfer the filename from
- ; the DTA to the DIR_LIST
- MOV BYTE PTR [DI],'.' ;Set filename.ext period
- INC DI
- MOV CX,3 ;3 byte file extension to move
- REP MOVSB ;Transfer the file extension
- MOV SI,OFFSET DTA_DATE ;Transfer the date the file
- MOVSW ;was created or last updated
- MOV SI,OFFSET DTA_FSIZE ;Transfer size of file (bytes)
- MOVSW ;Least-significant part of the
- MOVSW ;size is stored in 1st word
- ;
- ADD BX,20 ;Each entry in DIR_LIST uses
- MOV LAST_ENTRY,BX ;20 bytes. Update LAST_ENTRY
- INC WORD PTR FILE_COUNT ;1 more file in the list
- ;
- MOV DX,OFFSET FCB_FLAG ;Reset DS:DX to the start of
- MOV AH,12H ;our FCB Area and go looking
- INT 21H ;for the next match-up in the
- ; disk directory
- OR AL,AL ;Any more match-ups?
- JZ DIR_XFER ;If so, jump back baby
- END_XFER:
- RET
- GET_ENTRIES ENDP
- ;
- ; The following code uses a bubble sort to establish a linked list of entries
- ; in DIR_LIST. The link pointers are stored in the first word of each entry in
- ; DIR_LIST and the variable FIRST_ENTRY points to the first entry in the sorted
- ; list. The link pointer in this first entry points to the second entry, etc.
- ; The last entry in the sorted list has a link pointer value of zero.
- ;
- ; At the start of each pass in the bubble sort, DI is set to the first entry
- ; in the sub-list sorted so far and SI points to the DIR_LIST entry being
- ; added to the sorted sub-list. During the pass, DI moves up the sorted sub-
- ; list and the filename beginning at [DI+02] is compared to the filename at
- ; [SI+02]. BX points to the previous value of DI. When the correct location
- ; for the SI entry is found in the sorted sub-list (entry in BX < entry in SI
- ; < entry in DI), the link pointer in BX is set to the offset of the SI entry
- ; and the link pointer in SI is set to the offset of the DI entry.
- ; i.e., BX points to SI and SI points to DI.
- ; A value of DI = 0 indicates that we are at the top of the sorted sub-list.
- ;
- SORT_ENTRIES PROC NEAR
- MOV SI,OFFSET DIR_LIST ;Initially, select the first
- ; entry in DIR_LIST for sort
- CMP SI,LAST_ENTRY ;If no entries in DIR_LIST,
- JE SHORT END_SORT ;bypass the sort step
- NEW_PASS:
- MOV DI,OFFSET FIRST_ENTRY ;Point DI to the first entry
- ; in the sorted sub-list of
- ; DIR_LIST entries
- NEXT_COMPARE:
- MOV BX,DI ;Update DI, retaining previous
- MOV DI,[BX] ;value of DI in BX
- OR DI,DI ;Are we at the top of the
- JZ FIX_PTRS ;sub-list? If so, jump
- PUSH SI
- PUSH DI
- LEA SI,[SI+02] ;If not, compare the filenames
- LEA DI,[DI+02] ;pointed to by SI and DI
- MOV CX,12 ;12 chars in "filename.ext"
- CLD ;Set 'forward' CMPSB operation
- REPE CMPSB ;Compare until different:
- ; (value in SI - value in DI)
- ; i.e. result is positive if
- ; SI entry > DI entry
- POP DI
- POP SI
- JA NEXT_COMPARE ;If the entry in SI is alpha-
- ; betically greater than the
- ; entry in DI, try the next
- ; entry in the sorted sub-list
- FIX_PTRS:
- MOV [BX],SI ;Point BX entry to SI entry
- MOV [SI],DI ;Point SI entry to DI entry
- ADD SI,20 ;Point SI to next entry in
- ; DIR_LIST to be sorted
- CMP SI,LAST_ENTRY ;Proceed with a new pass only
- JB NEW_PASS ;if we are not at the end of
- ; DIR_LIST
- END_SORT:
- RET
- SORT_ENTRIES ENDP
- ;
- ; The screen display is going to list the files in two columns. To do this we
- ; must know the file entry in DIR_LIST which is half-way down the list, as
- ; this will be displayed on the right-hand side of the screen against the first
- ; entry in the list which will be displayed on the left-hand side, and so on
- ; down the list. So here goes:
- ;
- FIND_MIDDLE PROC NEAR
- MOV CX,FILE_COUNT
- SAR CX,1 ;CX = FILE_COUNT / 2
- JZ NO_RHS
- ADC CL,00 ;Add 0 to CL ???
- MOV BX,OFFSET FIRST_ENTRY
- NEXT_ENTRY:
- MOV BX,[BX] ;Find the entry which is half-
- LOOP NEXT_ENTRY ;way down the sorted DIR_LIST
- MOV AX,[BX]
- MOV MID_ENTRY,AX ;Save the list mid-point
- XOR AX,AX
- MOV [BX],AX ;Set the link pointer in the
- ; mid-point entry to zero
- NO_RHS:
- RET
- FIND_MIDDLE ENDP
- ;
- ; Read the File Allocation Table information. See 1, C-1, C-2, C-6 through C-9,
- ; and D-26.
- ;
- GET_FAT_INFO PROC NEAR
- PUSH DS ;DS is destroyed by next
- ; DOS function call
- MOV AH,1BH ;Get DOS File Allocation Table
- INT 21H ;information. See 1, A-12
- ; On return, DS:BX points to FAT i.d. byte
- ; AL = number of sectors per cluster
- ; CX = number of bytes per sector
- ; DX = number of clusters (allocation units)
- POP DS ;Restore DS to Data Segment
- XCHG CX,DX ;Swap values in CX and DX
- XOR AH,AH ;Zero out AH
- MUL DX ;Multiply the no. of sectors
- ; per cluster (AX) by the
- ; physical sector size (DX)
- PUSH AX ;Save AX = number of bytes per
- ; cluster
- PUSH CX ;Save number of clusters (for
- ; future use as loop counter)
- MOV AH,2 ;Read sectors into memory
- MOV AL,2 ;Read two sectors
- MOV BX,OFFSET DIR_LIST+800H ;Point ES:BX to buffer address
- ; at 2K bytes above DIR_LIST
- XOR CH,CH ;Read track zero
- MOV CL,2 ;Start reading at sector 2
- XOR DH,DH ;Read side zero (head 0)
- MOV DL,FCB_DRIVE ;1=A, 2=B, etc.
- DEC DL ;0=A, 1=B, etc.
- INT 13H ;Diskette I/O BIOS interrupt
- MOV AL,DIR_LIST+800H ;Store first byte of FAT in
- MOV DISK_FORMAT,AL ;DISK_FORMAT. See 1, C-7
- POP CX ;Number of clusters on disk
- XOR AX,AX ;AX is used to accumulate the
- ; number of clusters unused or
- ; available on the disk
- MOV SI,02 ;Point to the cluster which
- ; begins mapping of the data
- ; area on the disk (see 1, C-7)
- NEXT_CLUSTER:
- MOV DI,SI ;DI = SI
- SHR DI,1 ;DI = SI/2
- ADD DI,SI ;DI = 1.5 * SI, i.e. the byte
- ; offset from the beginning of
- ; the FAT corresponding to the
- ; cluster numbered SI
- MOV DI,[BX+DI] ;The address of the FAT entry
- TEST SI,01 ;If SI is even (right-most
- JZ EVEN_CLUSTER ;bit is 0), jump
- SHR DI,1 ;Keep the 12 high-order bits
- SHR DI,1 ;of DI. This is the fastest
- SHR DI,1 ;way to shift right 4 times,
- SHR DI,1 ;dividing DI by 16 (8 clocks)
- EVEN_CLUSTER: ;See 1, C-8, C-9
- AND DI,0FFFH ;Check 12 low-order bits for
- JNZ IN_USE ;000 (unused space)
- INC AX ;AX = number of clusters not
- ; in use on the disk
- IN_USE:
- INC SI ;Point to the next cluster in
- ; the File Allocation Table
- LOOP NEXT_CLUSTER
- POP DX ;DX = number of bytes per
- ; cluster
- MUL DX ;AX = number of bytes not in
- ; use on the disk. DX is set to
- ; most-significant word of
- ; AX*DX result. See 2, 6-114
- MOV FREE_SPACE,AX ;Save least-significant and
- MOV FREE_SPACE+02,DX ;most-sig. words of FREE_SPACE
- PUSH DS ;Save pointer to Data Seg
- XOR AX,AX
- MOV DS,AX ;Point DS to interrupt vectors
- MOV SI,[DS:INT24_SEG] ;Segment address for INT 24H
- MOV DI,[DS:INT24_OFF] ;Offset address for INT 24H
- PUSH DS ;Save interrupt vector DS
- PUSH CS
- POP DS ;Point DS to Code Segment
- MOV DX,OFFSET INT_24H ;Set interrupt vector for
- MOV AL,24H ;INT 24H to point to service
- MOV AH,25H ;routine in our Code Segment
- INT 21H ;See 1, D-28
- POP DS ;Reset DS to interrupt vectors
- MOV AH,0DH ;Disk reset - flushes all file
- INT 21H ;buffers. See 1, D-20
- MOV [DS:INT24_SEG],SI ;Reset interrupt vector for
- MOV [DS:INT24_OFF],DI ;INT 24H to original address
- POP DS ;Restore DS to Data Segment
- RET
- GET_FAT_INFO ENDP
- ;
- ; Replacement for DOS interrupt 24H, used in PROC GET_FAT_INFO:
- ;
- INT_24H PROC NEAR
- STI ;Set Interrupt Flag
- XOR AX,AX ;Zero out value of AX
- IRET ;Interrupt Return
- INT_24H ENDP
- ;
- ; Display the title line, including the requested drive and the available space
- ; on the disk. The value in FREE_SPACE must be converted from a 4-byte binary
- ; number to a multi-byte ASCII unpacked number before it can be displayed !!
- ;
- DISPLAY_TOP PROC NEAR
- MOV DX,OFFSET CR_LF
- MOV AH,9 ;Print string at DX,
- INT 21H ;terminated by $ sign
- ;
- ; Print the title line, including the requested drive and the unused
- ; (available) space on the diskette.
- ;
- MOV DX,OFFSET TLINE_1 ;Display the first part of the
- MOV AH,9 ;display line (up to the no.
- INT 21H ;of bytes of free space)
- MOV SI,FREE_SPACE ;Create an ASCII string of
- MOV DI,FREE_SPACE+02 ;decimal numbers equivalent to
- CALL BIN_TO_ASCII ;the binary number stored in
- ; SI:DI, and display the string
- MOV AH,2AH ;Get cur. date. Date returned
- INT 21H ;in CX:DX. See 1, D-31
- MOV AL,DH ;Move month (1-12) into AL
- AAM ;ASCII adjust for multiply
- XCHG AL,AH ;Put least-sig. byte first
- OR CURMONTH,AX ;Store month in display line
- MOV AL,DL ;Move day (1-31) into AL
- AAM
- XCHG AL,AH
- OR CURDAY,AX ;Store day in display line
- MOV AX,CX ;Move year (1980-2099) into AL
- SUB AX,1900 ;Convert to (80-199)
- AAM
- XCHG AL,AH
- OR CURYEAR,AX ;Store year in display line
- MOV AH,2CH ;Get cur. time. Time returned
- INT 21H ;in CX:DX. See 1, D-31
- MOV AL,CH ;Move hours (0-23) into AL
- AAM
- XCHG AL,AH
- OR CURHOUR,AX ;Store hours in display line
- MOV AL,CL ;Move minutes (0-59) into AL
- AAM
- XCHG AL,AH
- OR CURMIN,AX ;Store minutes in display line
- ;
- MOV DX,OFFSET TLINE_3 ;Display some more of the
- MOV AH,9 ;title line
- INT 21H
- ;
- ; Determine the disk format and display the appropriate message:
- ;
- MOV BL,DISK_FORMAT
- MOV SI,OFFSET FAT_FLAG
- CLD ;Set 'forward' LODSB operation
- NEXT_FORMAT:
- LODSB ;Load byte addressed by SI
- ; into AL and increase SI
- OR AL,AL ;If zero, we didn't match up
- ; any valid format type
- JZ SHORT DISP_FORMAT
- CMP AL,BL ;Check byte from table against
- ; first byte from FAT
- JZ SHORT DISP_FORMAT
- ADD SI,02 ;Skip past the improper msg.
- JMP NEXT_FORMAT ;Check for next format type
- DISP_FORMAT:
- LODSW ;Load word addressed by SI
- ; into AX and increase SI, i.e.
- MOV DX,AX ;Pick up message address,
- MOV AH,9 ;store address in DX, and
- INT 21H ;display the message
- MOV DX,OFFSET CR_LF ;Carriage return, line feed
- MOV AH,9
- INT 21H
- ; Display the column titles on the left-half of the screen and, if
- ; appropriate, also display them on the right-half of the screen
- ;
- MOV DX,OFFSET COL_TITLES
- MOV AH,9
- INT 21H
- CMP WORD PTR MID_ENTRY,0 ;Are there any entries for the
- JZ LINE_FEED ;right-half of the screen?
- MOV DX,OFFSET TAB_8
- MOV AH,9
- INT 21H
- MOV DX,OFFSET COL_TITLES
- MOV AH,9
- INT 21H
- LINE_FEED:
- MOV DX,OFFSET SKIP_1
- MOV AH,9
- INT 21H
- RET
- DISPLAY_TOP ENDP
- ;
- ; Display the lines containing the filenames, their sizes, and dates of last
- ; update. File sizes are stored as 4-byte binary numbers. The least-significant
- ; part of the number is in the first 2 bytes.
- ;
- LIST_ENTRIES PROC NEAR
- NEXT_LINE:
- MOV BX,FIRST_ENTRY ;Point BX to the LHS entry to
- OR BX,BX ;be displayed
- JZ END_OF_LIST
- MOV AX,[BX] ;Adjust FIRST_ENTRY so that it
- MOV FIRST_ENTRY,AX ;points to the following entry
- ; to be displayed on the LHS
- CALL DISPLAY_ENTRY
- MOV BX,MID_ENTRY ;Point BX to the RHS entry to
- OR BX,BX ;be displayed
- JZ END_OF_LINE
- MOV DX,OFFSET TAB_6 ;Leave 6 spaces down the
- MOV AH,9 ;middle of the screen,
- INT 21H ;separating LHS and RHS.
- MOV AX,[BX] ;Adjust MID_ENTRY so that it
- MOV MID_ENTRY,AX ;points to the following entry
- ; ;to be displayed on the RHS
- CALL DISPLAY_ENTRY
- END_OF_LINE:
- MOV DX,OFFSET CR_LF
- MOV AH,9
- INT 21H
- JMP NEXT_LINE
- END_OF_LIST:
- RET
- LIST_ENTRIES ENDP
- ;
- ; Reset the default drive to its original status, as saved in DEF_DRIVE:
- ;
- RESET_DRIVE PROC NEAR
- MOV DL,DEF_DRIVE ;Reset the default drive to
- MOV AH,0EH ;the value stored in DEF_DRIVE
- INT 21H
- RET
- RESET_DRIVE ENDP
- ;
- ; Display the filename, extension, size, and date of last update for the file
- ; in DIR_LIST pointed to by BX.
- ;
- DISPLAY_ENTRY PROC NEAR
- MOV CX,12
- XOR DI,DI
- NEXT_CHAR:
- MOV DL,[BX+DI+02] ;Display the filename, period
- MOV AH,02 ;separator, and file extension
- INT 21H ;(12 bytes), 1 byte at a time
- INC DI ;Point to next character
- LOOP NEXT_CHAR ;Loop controlled by CX
- PUSH BX
- MOV SI,[BX+16] ;SI = least-significant word &
- MOV DI,[BX+18] ;DI = most-significant word of
- ; binary number to be unpacked
- CALL BIN_TO_ASCII
- POP BX
- MOV DX,OFFSET TAB_4 ;Leave 4 spaces between the
- MOV AH,9 ;file size and the date of
- INT 21H ;last update
- MOV AX,[BX+14] ;AX = the date of last update
- CALL DISPLAY_DATE
- RET
- DISPLAY_ENTRY ENDP
- ;
- ; Interpret AX as a date and display it on the screen as an 8 character string:
- ; (MM/DD/YY)
- ;
- DISPLAY_DATE PROC NEAR
- OR AX,AX
- JNZ REAL_DATE
- MOV DX,OFFSET TAB_8 ;Word at AX is all-zero so
- MOV AH,9 ;display 8 blanks instead of
- INT 21H ;a real date value
- RET
- REAL_DATE:
- PUSH AX ;Save date value stored in AX
- AND AX,0000000111100000B ;Extract the month value from
- MOV CL,5 ;the date. See 1, C-5
- SHR AX,CL ;Get rid of 5 least-sig. bits
- CALL DISPLAY_CHARS
- MOV DL,'/' ;Display the slash separator
- MOV AH,2 ;between the month and day
- INT 21H ;of last update
- POP AX ;Restore date value to AX
- PUSH AX ;and save it again
- AND AX,0000000000011111B ;Extract the day value from
- CALL DISPLAY_CHARS ;the date. No shift necessary
- MOV DL,'/'
- MOV AH,2 ;Slash is between day and year
- INT 21H ; of last update
- POP AX
- AND AX,1111111000000000B ;Extract the year value from
- MOV CL,9 ;the date. Get rid of the 9
- SHR AX,CL ;least-significant bits in AX
- ADD AX,80 ;Zero value corresponds to
- CALL DISPLAY_CHARS ;1980. See 1, C-5
- RET
- DISPLAY_DATE ENDP
- ;
- ; Convert the binary number stored in AX to a decimal number and display it as
- ; 2 digits.
- ;
- DISPLAY_CHARS PROC NEAR
- AAM
- OR AX,3030H ;30H = 48 = ASCII value of 0
- PUSH AX
- MOV DL,AH ;Display first digit of date
- MOV AH,2 ;field
- INT 21H
- POP AX
- MOV DL,AL ;Display second digit of date
- MOV AH,2 ;field
- INT 21H
- RET
- DISPLAY_CHARS ENDP
- ;
- ; Convert the 2-word binary number stored in SI:DI (where SI contains the
- ; least-significant part of the binary number and DI contains the
- ; most-significant part) into a multi-byte string containing the ASCII
- ; representation of the corresponding decimal number, and display the ASCII
- ; string on the screen at the current cursor location.
- ;
- BIN_TO_ASCII PROC NEAR
- XOR AX,AX
- MOV BX,AX
- MOV BP,AX
- MOV CX,32 ;32 bits to convert
- NEXT_BIT:
- SHL SI,1
- RCL DI,1
- XCHG AX,BP
- CALL BTOA_SUBR4
- XCHG AX,BP
- XCHG AX,BX
- CALL BTOA_SUBR4
- XCHG AX,BX
- ADC AL,0
- LOOP NEXT_BIT
- MOV CX,1B10H
- CALL BTOA_SUBR1
- MOV AX,BX
- CALL BTOA_SUBR1
- MOV AX,BP
- CALL BTOA_SUBR1
- RET
- BIN_TO_ASCII ENDP
- ;
- ;
- ;
- BTOA_SUBR1 PROC NEAR
- PUSH AX
- MOV DL,AH
- CALL BTOA_SUBR2
- POP DX
- CALL BTOA_SUBR2
- RET
- BTOA_SUBR1 ENDP
- ;
- ;
- ;
- BTOA_SUBR2 PROC NEAR
- MOV DH,DL
- SHR DL,1
- SHR DL,1
- SHR DL,1
- SHR DL,1
- CALL BTOA_SUBR3
- MOV DL,DH
- CALL BTOA_SUBR3
- RET
- BTOA_SUBR2 ENDP
- ;
- ;
- ;
- BTOA_SUBR3 PROC NEAR
- AND DL,0FH
- JZ SHORT TARGET
- MOV CL,0
- TARGET:
- DEC CH
- AND CL,CH
- OR DL,48 ;48 = ASCII value of zero
- SUB DL,CL ;Display the character in DX
- MOV AH,2 ; on the screen
- INT 21H
- RET
- BTOA_SUBR3 ENDP
- ;
- ;
- ;
- BTOA_SUBR4 PROC NEAR
- ADC AL,AL
- DAA
- XCHG AL,AH
- ADC AL,AL
- DAA
- XCHG AL,AH
- RET
- BTOA_SUBR4 ENDP
- MAIN ENDP
- CODE ENDS
- ;
- STACK SEGMENT PARA STACK 'CODE'
- DB 128 DUP (0) ;128 Byte Stack Space
- STACK ENDS
- END MAIN