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