home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
sampler0
/
mdir.asm
< prev
next >
Wrap
Assembly Source File
|
1986-02-11
|
67KB
|
1,655 lines
title MDIR.ASM - Memory resident DIRectory
COMMENT |
I've long desired a memory resident directory routine. This code began
life as SD.ASM, whose original comments are reproduced below.
The routine will put the directory on the "alternate" screen if
two monitors are available. It does NOT check to see if the
second monitor is actually installed.
Usage:
MDIR [2]
where the [2] indicates that both a color and a monochrome
monitor are available on the system. If you tell the routine
that both are available, the directory will be printed to the
monitor that is NOT currently being used.
If only ONE monitor is installed, or if MDIR is executed without
the '2' on the command line, then the directory will be shown on
the monitor that is currently being used. If this is the case,
MDIR will "save" the screen currently being used, and restore it
when done.
To use MDIR once it has been installed, it is activated by
pressing either the <Alt><8> or the <Alt><9> key combinations
together (where the number keys are those above the alpha keys on
the keyboard, NOT the ones from the numeric keypad).
If you press the <Alt><8> keys, the directory will be displayed
in alphabetical order. If you press <Alt><9>, MDIR will prompt
you for a "command line" to be used. The command line can
duplicate a command given to the DOS DIR command. For example:
[assume the <Alt><9> keys have been pressed together]
MDIR prompt your response results
╔════════════╧═════════════╗ ╔═════════╧══════════╗ ╔═════════╧══════════╗
command line (/H for help): *.* all files in the current
directory
\masm\files all files in the sub-
directory named
\masm\files
*.pas any file in the current
directory with the
extension .PAS
\masm\files\*.arc any file in the sub-
directory named
\masm\files with the
extension .ARC
b:*.* all files in the
current directory
on drive B:
In addition, there are several options, detailed below, that are
triggered by the / switch. /H given at the command line will list
the options, which deal with including hidden & subdirectory files, and
with the way in which the file list is sorted.
The ability to handle path names was added to the original SD.ASM code.
That approach was taken from:
RED.ASM John Dickinson, "REDirecting Your Files",
PC Magazine, Vol. 4, No. 4 (February 19, 1985)
Moving files between directories without
copy/erase
CAVEATS:
1. Because MDIR reads information from the disk, avoid
"triggering" this utility when an operating program
is working with the disks -- results can be
unpredictable (and fatal).
2. The code is set up to prevent MDIR from being triggered twice
in a row -- a key other than the "trigger" keys must be pressed
between uses.
3. The "trigger" keys are defined by EQUates near the top of the
code -- (see KEY1 and KEY2). If they interfere as currently
defined, please reassign 'em.
4. MDIR "sets up" the actual directory routines to use
one of the unused interrupts (currently INT 67h) -- please use
another interrupt if INT 67h interferes with any software that
you are currently using. This interrupt approach was taken to:
a: allow the directory routine to read the keyboard without
calling its own routine;
b: to help isolate the directory routine from the effects
of pressing the <Alt><8 or 9> key combination again before
the directory routine has completed its work; and
c: it prevents MDIR from being REinstalled (MDIR will not
install if Int 67h is already in use).
5. MDIR currently saves space for 256 directory entries
(see the variable DIRBUF at the end of the stay-resident code).
That's more than enough (by a factor of two) to display the files
in my most outrageous directory -- but be forewarned, DOS can
hold more than 256 entries in a subdirectory. The problem with
increasing the storage space is that it requires 22 bytes per
entry -- and the storage space becomes part of the resident file.
Thus, if we increased DIRBUF to 1024 entries, an extra 16,896
bytes of storage would stay resident when MDIR is installed. I
prefer my resident utilities to be as small as possible (that's
why I detest stay-resident programs written in high-level
languages), so I've limited the space that mine requires.
The routine currently does not bother to check if you've got
more entries than space has been allocated for -- if you do,
you'll crash MDIR's stack (see below), and possibly memory
allocated to your operating program. In any case, if you use
MDIR to display a directory with more entries than you've got
reserved, death and destruction (or at least a good
machine crash) can result.
6. The stack that MDIR uses when it is working is set at 150 words
(see STACKTOP at the end of the stay-resident code). This
should be phenominally generous.
7. MDIR does its best to trap disk errors -- it uses low-level
BIOS routines to initially find out if the requested disk
is ready. This allows MDIR to bypass the dread DOS error
"disk not ready" -- which will cause a resident program to
crash the machine. MDIR does NOT check to see if a hard drive
is ready.
8. Some software stores information in the alternate pages of
the video memory IF you are using a color/graphics adaptor
(PC-Write, for example, stores its help screens in the memory
of the other c/g pages). MDIR only saves the current video
page, so you can scramble help screens when MDIR switches
monitors.
9. MDIR doesn't check if a drive has been ASSIGNed. If you
request a directory for drive B:, MDIR will look for physical
drive B:.
I've used this routine with a variety of software, including:
Lotus' 123
PC-Write
PC-TALK
TURBO Pascal
This is one of several "two screen" utilities that I've been working on --
since I've got two monitors, I am tired of effectively wasting one.
MDIR may still have some bugs -- but then, you've got the source
code, so please solve 'em (and let me know what you find). It
ain't perfect, but it's small and efficient, and it seems to work for me.
Please let me know about any bugs/comments that you have via
Gene Plantz' IBBS, 312-882-4227.
Mike Pechnyo
ID1206
<><><><><><><><><><><><><><><><> SD.ASM COMMENTS <><><><><><><><><><><><><><><>
SD [d:][filename[.ext]] [options]
[filespec] same as for DIR command
[options] * /A - List hidden files.
* /E - Without screen erase.
* /W - wait when screen full.
* /R - Include directory entries djm
* /M - Display Modified entries only djm
/X - Sort by extension.
/S - Sort by size.
/D - Sort by date/time.
/N - Do not sort, original order.
/H - Help - only display options djm
Default = *.* sorted by name.ext with screen erase.
* - Option may be combined with other options.
This source file was created from an object file obtained
from Gene Plantz's BBS in Chicago. The original file name
was SD.HEX. I then used DEBUG and CAPTURE to get the first
dis-assembly which was then edited with WORDSTAR to create
a source that when assembled using MASM would duplicate the
original object file.
Comments have been added and I do hope they are helpful.
I have made several modifications to the first version and
am continuing to add comments. This source file is an
excellent example for anyone wishing to learn 8086/8088
assembly language. Use at your own risk and feel free to
share this file with your friends.
I certainly wish that John Chapman would publish his
source file. His comments are sure to be more meaningful
than mine could ever be. Some of the conversion routines
are very elegant, but difficult to understand. As far as
I'm concerned, PRINTDD is magic.
Several modifications have been made. They are:
1. Filespecs are processed like DIR does.
2. No sort option was added. /N
3. Pause when screen full option added. /P changed to /W by DJM
4. Number of files found is printed.
Ted Reuss
Houston, TX
SDIR Version 2.2 The GETFREE Subroutine was updated for DOS 2.0
April 1, 1983 by Jack Y. Fong
Changes are denoted by "JYF" at the end of changed lines.
I (Dave Mc Laughlin) have also made several modifications: (V 3.0)
Pause is now standard unless /P is entered to defeat
Color is now supported on color monitors
Free space is now reported at the bottom, along with
directory total (to give an idea of how many diskettes
may be required for backup)
Volume and current directory are shown on the top line
(my apologies to Capitol PC Club for removing their logo)
Modified files are shown with a + sign in place of the .
The /R option (show sub directory names) has been added
The /P option was changed to /W(ait) and /M (modified only) added
<><><><><><><><><><><><><><> SD.ASM COMMENTS END <><><><><><><><><><><><><><><>
All ANSI.SYS calls have been removed from SD.ASM (done to speed up
screen accesses) mp 1-6-86
|
SUBTTL EQUATES & STRUCTURES
PAGE
IF1
DOSCALL MACRO FUNC,PARM1
.xcref
F_C = FUNC
IFNB <PARM1>
IF F_C EQ 2 OR (F_C GE 4 AND F_C LE 6) OR F_C EQ 14 OR F_C EQ 46
MOV DL,PARM1
ELSE
MOV DX,OFFSET PARM1
ENDIF
ENDIF
MOV AH,FUNC
INT 21H
.cref
ENDM
ENDIF
.SALL ;supress all macro expansions
; PC-DOS INTERRUPT 21H FUNCTION CODES
;
KEY1 equ 127 ; Alt 8 key (number key from on top of the keyboard)
KEY2 equ 128 ; Alt 9 key (ditto)
; KEY1 will display a sorted directory of the
; current drive/subdirectory
; KEY2 will prompt for a "command line" which
; can be used to specify another subdirectory,
; drive, or files (wildcards in the file names
; are acceptable
@CHROUT EQU 2 ;display char in DL
@KEYIN EQU 8 ;kybd input w/o echo
@STROUT EQU 9 ;print string terminated with $
@CKEYIN EQU 12 ;clr kybd bufr & do inp.func in AL
@VOLLAB EQU 11h ;search for first matching file, used for VOLUME LABEL
@SRCH1 EQU 4Eh ;search for first dir entry mp
@SRCH2 EQU 4Fh ;search for next dir entry mp
@GETDSK EQU 25 ;get default disk drive
@SETDTA EQU 26 ;set disk transfer addr
@FATAD2 EQU 28 ;get FAT of drive # in DL
@PARSEF EQU 41 ;parse filename
@GETDTE EQU 42 ;get system date
@GETTME EQU 44 ;get system time
@DSKFSP EQU 36H ;get disk free space JYF
@GETVER EQU 30H ;get version number JYF
@GETDIR EQU 47H ;get directory djm
CR EQU 0DH ;carriage return
LF EQU 0AH ;line feed
; PC-DOS packed date <yyyyyyym mmmddddd>
P_DTE RECORD P_YR:7,P_MO:4,P_DY:5
; PC-DOS packed time <hhhhhmmm mmmsssss>
P_TME RECORD P_HR:5,P_MI:6,P_2S:5
DIRNTRY STRUC ;directory entry structure
LNK DW 0 ;ptr to next entry
NAM DB 8 DUP(0) ;filename
SEP DB '.' ;separator
EXT DB 3 DUP(0) ;extension
TME DW 0 ;time
DTE DW 0 ;date
SZL DW 0 ;low word of size
SZH DW 0 ;high word of size
DIRNTRY ENDS
CODE_SEG segment
assume cs:CODE_SEG,ds:CODE_SEG
org 100h ; COM program format
BEGIN: jmp SWAP_VECTORS ; Initialize vectors and attach to DOS
;
getout: nop
immed: db 0EAh
redef16 label word
ROM_KB_INT dd ? ; Double word to save address of
; ROM-BIOS keyboard interrupt
INT24_LOC dd ? ; to save address of INT24 location
video_hold dw 2000 dup(?) ; storage to hold the old screen
in_use db 1
shift_key db 0
old_equip dw 0
old_page db 0
old_mode db 0
old_pos dw 0
old_size dw 0
DIRWRK DB 64 DUP (' ') ;directory work area djm
ROOT DB '* * ROOT * *',18 DUP (' ') ; djm
DIRSW DB 0 ;0=this is not a directory entry djm
TOTL DW 0 ;low order word of total size used djm
TOTH DW 0 ;high order djm
C1LNK DW 0 ;ptr to row 1, column 1
C2LNK DW 0 ;ptr to row 1, column 2
NBRFILS DW 0 ;# of files or detail lines
SRTFLG DB 0 ;if = 0 then sort else no sort
CLSFLG DB 0 ;if = 0 then clear screen
EXTFLG DB 0 ;if <> 0 then sort by ext
SIZFLG DB 0 ;if <> 0 then sort by size
PSEFLG DB 0 ;if <> 0 then pause when screen is full
DTEFLG DB 0 ;if <> 0 then sort by date/time
MODFLG DB 0 ;if <> 0 then display modified only djm
OPTFLG DB 0 ;if <> 0 then display options (no directory)djm
command_len db 0
command_line db 64 dup(0) ; storage for "command line" typed in
source_path db 65 dup(0)
DTA DB 43 DUP(0) ;Disk Transfer Area used
old_FILNAME equ DTA+8
old_FILTIME EQU DTA+30 ;directory search.
old_FILSIZE EQU DTA+36
old_FILATR EQU DTA+19
FILNAME EQU DTA+30 ;by SRCHDIR for the
FILTIME EQU DTA+22 ;directory search.
FILSIZE EQU DTA+26
FILATR EQU DTA+21
other_dir db 0 ; 0 indicates neither drive nor path specified
; 1 = path only specified
; 2 = drive (and maybe path) specified
retries db 0 ; # of times the disk was retried
new_mask db 0
new_mode dw 0 ; and for new mode, with video select chosen
scrn_cols db 80 ; screen columns available mp
old_mask dw 0FFFFh ; old equipment flag
DIRLNK DW DIRBUF ;ptr to next opening in DIRBUF
two_screens db 0 ; non-zero if more than one screen is available mp
PERMPSE DB 1 ; permanent pause flag
MAXDRIVE db 0 ; number of floppy drives
DIR_ATTR db 16 ; directory attribute
LPERSCR EQU 25 ;Lines per screen
LINCNT DB LPERSCR-4 ;Number of lines left
PSEMSG DB 'Strike a key when ready . . . $' ; djm
HDNG1 DB 'Vol: '
VOLLOC DB 13 DUP (' ') ;put volume label here djm
DB 'Dir: '
DIRLOC DB 27 DUP (' ') ;put directory name here djm
DB 3 DUP (' '),'Date: ' ; djm
D_MM DW '00' ;Month
DB '/'
D_DD DW '00' ;Day
DB '/'
D_YY DW '00' ;Year
DB ' '
DB 'Time: '
T_HH DW '00' ;Hours
DB ':'
T_MM DW '00' ;Minutes
DB CR,LF
CRLF DB CR,LF,'$'
HDNG2 DB 'Filespec.ext Bytes- --Last Change--$'
DB 8 DUP(' ')
SPACES DB '$'
HDNG3 DB ' File(s)',8 DUP (' '),'$'
HDNG5 DB ' Directory Total',9 DUP (' '),'$' ; djm
HDNG6 DB ' Free Space'
DB CR,LF,'$'
OPTHDG DB ' S O R T E D D I R E C T O R Y',cr,lf
DB CR,LF
DB ' Display Options:',cr,lf
DB ' /A Include hidden files',cr,lf
DB ' /R Include directory names',cr,lf
DB ' /M Show only files that have been ',cr,lf
DB ' modified since last backup',cr,lf
DB ' /E Don',39,'t erase screen before display',cr,lf
DB ' /W Wait when screen is full',cr,lf,cr,lf
DB ' Sort Options -- Sort by:',cr,lf
DB ' /X eXtension',cr,lf
DB ' /S Size',cr,lf
DB ' /D Date and time',cr,lf
DB ' /N No sort',cr,lf,'$'
error_msg db 'There is a problem with drive '
error_drive db ' :. (The door may be open).',13,10,10
error_end db 'Please fix the problem, and press any key '
db ' ..... OR reboot the computer',13,10,'$'
abort_message db 13,10,10,'MDIR is aborting ...',13,10,'$'
SUBTTL DISK TRANSFER AREA & FREE SPACE ENTRY DEFS
PAGE
XFCB DB -1,7 DUP(0),11 DUP('?'),25 DUP(0)
old_ATTRIB EQU XFCB+6 ;file attribute
old_DRVNBR EQU old_ATTRIB+1 ;drive # (1=A, 2=B, etc.)
ATTRIB DB 0 ;file attribute
DRVNBR DB 0 ;drive # (1=A, 2=B, etc.)
FREESPC DW 0 ;Free space entry.
DB '*FREE SPACE*',4 DUP(0)
LOSIZE DW 0 ;of free space
HISIZE DW 0 ;of free space
command_question db 'command line (/H for help): $'
DosSSeg dw 0
DosSP dw 0
command_location dw 0
backslash db '\'
stars db '*.*',0
VALID_IN db 'abcdefghijklmnopqrstuvwxyz,;=',9
VALID_OUT db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',4 dup(32)
VALID_NUM equ $ - VALID_OUT + 1
; MDIR_INT intercepts the keyboard interrupt and shows the directory
; if the KEY1 or KEY2 combination is pressed
;
MDIR_INT proc near
cmp ah,0 ; If Read Char request,
jne bail_out ; check the in_use flag
cmp cs:in_use,1 ; if MDIR is running, then use the
je ChrRqst ; old handler to read the key
bail_out:
jmp getout ; else jump to the real routine
ChrRqst:
push ds ; save just about every
push bx ; register that anyone ever
push cx ; heard of
push dx
push es
push si
push di
push bp
mov bx,cs ; set up DS & ES
mov ds,bx
mov es,bx
mov cs:DosSSeg,ss
mov cs:DosSP,sp
cli
mov dx,ds ; set MDIR to use its own
mov ss,dx ; stack
mov sp,offset stacktop
sti
do_interrupt:
int 67h ; call the interrupt using the old AH val
cmp al,0 ; is an extended key code returned?
jne return
cmp ah,KEY1 ; sorted dir of current subdir
je check_use
cmp ah,KEY2 ; prompt for command line
jne return
check_use: ; see if the in_use flag is on
cmp in_use,1 ; in_use = 1, MDIR not running
jne go_again ; in_use <>1, MDIR currently working
mov in_use,2
mov shift_key,ah ; save the key code used to call MDIR
call get_mdir ; and do the directory work
go_again:
mov ah,0 ; setup to read the keyboard again
jmp short do_interrupt ; and loop back. This will not "release"
; until a key other than KEY1 or KEY2 has
; been pressed (that new key will be
; returned to whatever program was running
; when MDIR interrupted.
return:
mov in_use,1 ; MDIR is done
cli
mov ss,cs:DosSSeg ; reset the stack to wherever it was
mov sp,cs:DosSP ; originally
pop bp ; and pop all of the saved registers
pop di ; (the new AX value is passed)
pop si
pop es
pop dx
pop cx
pop bx
pop ds
iret ; and complete the interrupt call
mdir_int endp
GET_MDIR proc near ; show the directories
;
; set up the displays
;
call init_video
;
; call directory routines
;
DO_DIRECTORIES:
call clear_vars ; clear any significant variables
cmp shift_key,KEY2 ; which key was pressed?
je A0a ; if KEY2, get a command line sequence
call get_drive ; else process current directory
mov command_location,offset stars
jmp short A0b
A0a:
call get_command ; get and process the command line
A0b:
cmp retries,2
jb A0c ; did the disk still fail?
mov si,offset abort_message
call show_line
jmp short A99a ; show the pause message
A0c:
call srchdir ;Search directory
cmp SRTFLG,0 ;Check if any sort
jz A1 ; option selected.
call lnkdirb ;Leave in original
jmp short A2 ; directory order.
A1: call srtdirb ;Sort by major key
A2: mov al,optflg ;See if only options wanted djm
or al,al ;See if H request for help djm
jz A3 ;Wasn't djm
mov si,offset OPTHDG
call show_line
jmp short A99 ;get out djm
A3: call getfree ;Get free space
call spltlst ;Set up for 2 columns
call prthdng ;Print headings
call prtdrvr ;Print detail lines
call prtnfls ;Print # of files
;
A99:
cmp two_screens,1 ; if there are two screens, then reset
je A100 ; the mode
A99a:
mov si,offset PSEMSG ;Display pause message.
call show_line
mov ah,0 ;Specify input function
int 67h ;Wait for key press
A100:
call restore_video ; restore the screens
ret
GET_MDIR endp
INIT_VIDEO proc near
;
; Save the current cursor position
;
mov ah,3 ; Call Func 3 of Int 10H
mov bh,0 ; to read cursor position
int 10h ; (page zero for color screen)
mov old_size,cx ; cursor start and stop lines
mov old_pos,dx ; cursor row, column
;
; get the video status
;
mov ah,0fh
int 10h ; get video mode
mov old_mode,al ; video mode
mov old_page,bh ; current page
cmp al,7 ; are we currently in monochrome mode?
jne SAVE_SCREEN
cmp old_size,0607h ; was the old cursor incorrectly set
; to the color cursor's size?
jne SAVE_SCREEN
mov old_size,0B0Ch ; start on 11, end on line 12
; note: DOS does not always set the proper cursor
; size upon startup - so this code catches the
; problem. See PC TECH JOURNAL, Dec., 1985,
; "The Dashed Cursor", Paul Pierce, p. 47.
;
; save the screen data
;
SAVE_SCREEN:
push ds
mov ax,0b000h
cmp old_mode,7 ; Did we switch from mono?
je COPY_SCREEN ; Yes, move data from mono
mov ax,0b800h
add ah,old_page ; c/g card page addresses are:
; Mode 0 Address B800
; 1 B900
; 2 BA00
; 3 BB00
COPY_SCREEN:
mov ds,ax
xor si,si ; Start at zero offset
push cs ; mov from DS:SI to ES:DI
pop es
mov di,offset VIDEO_HOLD
mov cx,2000 ; 2000 chars + attrs per screen
cld ; Make sure move is 'forward'
rep movsw ; Move Words with string instruction
pop ds
;
; Screen switch routine - Establish calling argument (AL) for Int 10h
;
cmp two_screens,1 ; if there are two screens, then go through
je switch_screens1 ; the mode setting exercise
mov ah,6 ; else clear the window
mov al,0
mov bh,7
xor cx,cx ; upper left corner
mov dh,24 ; row, column of lower right corner
mov dl,79
int 10h
mov ah,2
xor dx,dx
mov bh,old_page
int 10h ; set cursor to 0,0 position
jmp short INIT_DONE ; since there was only one screen,
; the setup is done
switch_screens1: ; set up the second screen
push ds
xor ax,ax ; set DS to 0
mov ds,ax
mov bx,word ptr ds:[410h] ; Current equipment flag to BX
pop ds
mov old_equip,bx
mov cx,bx ; Make a copy of the equipment flag in CX
and cx,30h ; Extract screen information
xor bx,cx ; Erase current screen information in BX
or bx,20h ; Set BX to color 80x25
mov al,2 ; Set AL for B&W 80x25 in Int 10h
cmp cx,30h ; Is current mono?
je SET_MODE1 ; Yes, switch to color
or bx,30h ; No, set BX for monochrome
mov al,7 ; Set AL for monochrome in Int 10h
SET_MODE1:
push ds
push ax
xor ax,ax ; set DS to 0
mov ds,ax
mov word ptr ds:[410h],bx ; Write BX to equipment flag
pop ax
xor ah,ah ; Use Func 0 of Int 10h to
int 10h ; change screen parameters
pop ds
INIT_DONE:
ret
INIT_VIDEO endp
RESTORE_VIDEO proc near ; return the video to its original mode
cmp two_screens,1 ; if there are two screens, then reset
jne short skip_page ; the mode
mov bx,old_equip
push ds ; save DS for use again
xor ax,ax ; set DS to 0
mov ds,ax
mov word ptr ds:[410h],bx ; restore the original equipment flag
pop ds
mov al,old_mode ; restore the original video mode
xor ah,ah ; Use Func 0 of Int 10h to
int 10h ; change screen parameters
cmp old_mode,7 ; is the screen monochrome?
je skip_page
mov ah,5
mov al,old_page
int 10h ; set the video page to the old value
;
; After screens are switched back, return the screen data
;
skip_page:
mov ax,0b000h
cmp old_mode,7 ; Did we switch back to mono?
je COPY_BACK ; yes, so copy to the mono screen
mov ax,0b800h
add ah,old_page ; restore to the proper video page
COPY_BACK:
mov es,ax
xor di,di ; Start at zero offset
push cs ; mov from DS:SI to ES:DI
pop ds
mov si,offset VIDEO_HOLD
mov cx,2000 ; 2000 chars + attrs per screen
cld ; Make sure move is 'forward'
rep movsw ; Move Words with string instruction
;
; Restore Cursor position
;
mov dx,old_pos ; restore the cursor position from the stack
mov ah,2 ; Use Func 2 of Int 10h to restore
mov bh,old_page
int 10h
;
; Restore Cursor size
;
mov cx,old_size ; restore the cursor size from the stack
mov ah,1 ; Use Func 1 of Int 10h to set cursor
int 10h
;
ret
RESTORE_VIDEO endp
SHOW_LINE proc near ; a simple-minded procedure to duplicate
; the INT 21h function to print a string
; terminated by a $. The routine uses
; the low-level BIOS Int 10h call rather
; than the DOS call.
push ax
print_loop:
mov al,byte ptr ds:[si]
cmp al,'$'
je print_done
call show_char
inc si
jmp short print_loop
print_done:
pop ax
ret
SHOW_LINE endp
SHOW_CHAR proc near ; print a character using BIOS Int 10h
; character should be in AL
mov ah,0Eh
int 10h ; tty write function
ret
SHOW_CHAR endp
CLEAR_VARS proc near ; clear all pertinent variables, and
; set initial values where needed.
push cs
pop es ; set up the extra segment
cld ; and make all moves forward
mov di,offset dirwrk ; fill DIRWRK with spaces
mov al,' '
mov cx,64 ; bytes to clear
rep stosb
mov di,offset dirsw
mov cx,offset new_mask
mov bx,offset dirsw
sub cx,bx
xor ax,ax
rep stosb
mov di,offset xfcb ; and clear a series of variables to 0
inc di
mov cx,offset freespc
mov bx,di
sub cx,bx
xor ax,ax
rep stosb
mov di,offset xfcb ; fill the FCB with question marks (?)
add di,8
mov al,'?'
mov cx,11
rep stosb
mov di,offset volloc ; and fill the headings with spaces
mov cx,13
mov al,' '
rep stosb
mov di,offset dirloc
mov cx,27
mov al,' '
rep stosb
mov t_mm,'00' ; clear the header variables used
mov t_hh,'00'
mov d_dd,'00'
mov d_mm,'00'
mov d_yy,'00'
mov scrn_cols,80 ; screen columns available
mov old_mask,0FFFFh ; old equipment flag
MOV ax,OFFSET DIRBUF ;Point to DIRBUF
mov dirlnk,ax ; reset the pointer
mov LINCNT,LPERSCR-4 ;Reset to # lines/screen
mov al,PERMPSE
mov PSEFLG,al
ret
CLEAR_VARS endp
GET_DRIVE proc near ; get the current drive
doscall @GETDSK ;AL <- default disk
inc al ;Increment drive #
mov DRVNBR,al ;Save drive #
call check_drive
ret
GET_DRIVE endp
CHECK_DRIVE proc near ; see if the requested drive (number
; stored in DRVNBR is available.
; Use the BIOS interrupt to avoid
; DOS errors, and read a sector from
; within the FAT (which ought to be
; good if the disk is to work)
push bx
push cx
push dx
cli
mov al,DRVNBR
cmp al,MAXDRIVE
ja drive_checked ; don't check if we're looking at a hard drive
; assume the hard drive is OK and ready
begin_check:
mov cx,3
recheck_loop:
push cx
mov bx,offset DIRBUF ; temporarily use the directory buffer
; ES:BX point to the input buffer
mov ah,2 ; read sectors into memory
mov al,1 ; # of sectors to read
mov ch,0 ; track
mov cl,4 ; sector to read -- somewhere in the FAT
mov dh,0 ; head #
mov dl,DRVNBR
dec dl ; so that drive # is in the form 0=A, 1=B
int 13h
pop cx ; restore the count
cmp ah,0
je drive_checked ; CF=1 means that the read failed, so retry
mov ah,0
int 13h ; reset the drive
loop recheck_loop
inc RETRIES
cmp RETRIES,1 ; see how many times we've been here
; IBM recommends trying a BIOS call 3 times
; to make sure the disk is ready. We
; give one retry if it doesn't work the
; first time. If it doesn't work the
; second time, MDIR aborts.
ja drive_checked
mov al,DRVNBR
add al,'@'
mov byte ptr error_drive,al
mov si,offset error_msg ; show the error message
call show_line
mov ah,0
int 67h ; wait for a keypress
jmp short begin_check
drive_checked:
sti
pop dx
pop cx
pop bx
ret
CHECK_DRIVE endp
GET_COMMAND proc near ; get a "command line" in response
; to KEY2
; limitted editing (backspace and left
; arrow only both delete the last
; character in the command line)
; is supported
push cs
push cs
pop ds
pop es
mov si,offset command_question
call show_line
mov di,offset command_line
cld
arg_loop:
mov ah,0
int 67h ; read the keyboard
cmp al,0
jnz check_key
cmp ah,'K' ; was the left arrow pressed?
jne arg_loop ; nope, so try again
mov al,8 ; it was the left arrow, so process it as a
; backspace
check_key:
cmp al,13 ; was the carriage return hit?
je arg_done ; if yes, the command line is done
mov ah,0Eh ; if not, print the character using teletype mode
int 10h ; tty write function
cmp al,8 ; backspace ???
jne other_key ; no, so process the key
dec command_len ; yes, so decrement the counters,
dec di ; and write a space + backspace
mov al,' ' ; over the character on the
mov ah,0eh ; screen
int 10h
mov al,8
mov ah,0eh
int 10h
jmp short arg_loop
other_key:
inc command_len
stosb ; save the byte
jmp short arg_loop
arg_done:
mov al,0 ; put a zero byte at the end of the string
stosb
mov si,offset crlf ; and space down twice
call show_line
mov si,offset crlf
call show_line
CHECK_CMD_LINE:
mov si,offset command_len ; command line length
xor ch,ch ; Zero CH
mov cl,[si] ; Move byte count to CL
cmp cl,0
jnz PARSE_CMD_LINE ; If CX is zero, there are no parameters
jmp BLANK_EXIT ; so handle this as if it were a KEY1 call
PARSE_CMD_LINE:
mov dx,cx ; Save byte count in dx
inc si ; Point to parameter area
mov di,si ; Copy SI to DI for cleanup routine
cld ; Set direction flag to forward
CLEAN_PARMS: ; Change valid delimiters to blanks, lower to upper case
lodsb ; Load each character to AL
push di ; Save DI on stack
mov di,offset VALID_IN ; Point to table of valid inputs
push cx ; Save CX on stack
mov cx,VALID_NUM ; Set CX to number of inputs to look for
repne scasb ; See if any are in AL
jcxz CLEAN_END ; If not, change nothing
mov bx,VALID_NUM ; Set up BX to point to valid output
sub bx,cx ; This will leave BX one off
mov al,VALID_OUT [bx - 1] ; Load the valid output to AL
CLEAN_END:
cmp al,'/' ; is it the switch character?
jne NOT_SWITCH ; (the switch character will
pop cx ; terminate the directory request
pop di ; of the command line)
mov al,0 ; make the first command an ASCIIZ
stosb
mov si,di ; point to the rest of the command line
call getargs ; and process the switch commands
sub dx,cx ; correct the string length
jmp short SWITCH_FOUND
NOT_SWITCH:
pop cx ; Restore CX
pop di ; Restore DI
stosb ; Store modified AL back to command line
loop CLEAN_PARMS ; Loop until CX is zero
;
SWITCH_FOUND:
mov cx,dx ; Restore number of bytes in cmd line
cmp cx,0
jne PARSE_BLANKS
jmp BLANK_EXIT
PARSE_BLANKS: ; remove blanks
mov al,' ' ; Set up to scan for first non-blank
mov di,offset command_line ; Set DI to command_line
FIND_PARMS: ; Start looking for parameters, load to program storage
repe scasb ; Scan while blanks
jnz FIX_DI ; if we've scanned everything
jmp BLANK_EXIT
FIX_DI:
dec di ; Adjust it to first non-blank byte
mov si,di
inc cx ; Adjust CX to compensate
mov di,offset source_path ; Set DI to parameter hold area
STORE:
lodsb ; Load each byte to AL
cmp al,' ' ; Is it a blank?
jz END_STORE ; Yes, end of this parameter
stosb ; No, store the byte to hold area
END_STORE:
loopnz STORE ; Keep looking {must come after labelled
; jump to properly decrement CX}
mov al,0
stosb ; make the string an ASCIIZ
mov other_dir,1 ; a path was specified
mov di, offset source_path
mov command_location,di
cmp byte ptr [di],'\' ; a '\' only indicates the root dir
jne NOT_ROOT ; has been requested
inc di
cmp byte ptr [di],0 ; is this just the root?
jne NOT_ROOT
mov si,offset stars ; get ready to move bytes
mov cx,4
rep movsb ; and copy the \*.* string
call get_drive
jmp short NOT_DIR
NOT_ROOT:
mov di, offset source_path + 1
cmp byte ptr [di],':' ; has a drive been specified?
je DRIVE_SPECD
call get_drive
jmp short COMMAND_GIVEN
DRIVE_SPECD:
mov other_dir,2 ; a drive (and maybe a path) has been
dec di ; specified
mov al,byte ptr [di]
sub al,'@'
mov DRVNBR,al ; save the drive number
call check_drive ; see if it is a legitimate drive
cmp retries,1 ; did the check fail?
ja NOT_DIR
inc di
inc di
cmp byte ptr [di],0 ; is the third byte the end-of-string?
jne COMMAND_GIVEN
mov si,offset backslash ; get ready to move bytes
mov cx,5
rep movsb ; and copy the \*.* string
COMMAND_GIVEN:
xor cx,cx
mov cl,DIR_ATTR ; see if a subdirectory only was
; requested. (With the DOS DIR
; command, if \MASM\FILES is a
; subdirectory, then 'DIR \MASM\FILES'
; will display all the files contained
; in that subdirectory.
DOSCALL @SETDTA,DTA ;Set DTA for dir. search
mov ah,@srch1
mov dx,command_location
int 21h
or al,al
jnz NOT_DIR
mov al,DIR_ATTR
cmp FILATR,al ;did we get a directory back?
je IS_DIR
mov other_dir,0 ; no, so clear the flag
jmp short NOT_DIR
IS_DIR:
mov al,0
mov cx,65 ; > DOS command line
mov di,offset source_path
repne scasb ; look for the end-of-string
dec di ; adjust DI to point to the last character
mov si,offset backslash ; get ready to move bytes
mov cx,5
rep movsb ; and copy the \*.* string
NOT_DIR:
ret
BLANK_EXIT: ; if a real command line wasn't specified,
; then use the default '*.*'
mov command_location,offset stars ; default command line
call get_drive ; get the current drive
ret ; and bail out, because no parameters
; were entered
GET_COMMAND endp
GETARGS PROC NEAR ; get any arguments after the / switch
; SI needs to point to the ASCIIZ argument string
B2: CMP BYTE PTR [SI],0
je b99
MOV AL,[SI] ;AL <- option letter
mov byte ptr [si],' ' ; replace the character with a space
CMP al,'/'
Je B11 ;If not a slash
AND AL,0DFH ;Force to upper-case
CMP AL,'A' ;Hidden & system files?
JNZ B31 ;Nope, try next one. djm
OR ATTRIB,2+4 ;Hidden & system djm
jmp short B11
B31: CMP AL,'R' ;directory entries? djm
JNZ B3 ;Nope, try next one. djm
OR ATTRIB,10H ;Directory djm
jmp short B11
B3: CMP AL,'E' ;Without screen erase?
JNZ B4 ;Nope, try next one.
MOV CLSFLG,AL
jmp short B11
B4: CMP AL,'S' ;Sort by size?
JNZ B5 ;Nope, try next one.
MOV SIZFLG,AL
jmp short B11
B5: CMP AL,'D' ;Sort by date/time?
JNZ B6 ;Nope, try next one.
MOV DTEFLG,AL
jmp short B11
B6: CMP AL,'X' ;Sort by extension?
JNZ B7 ;Nope, try next one.
MOV EXTFLG,AL
jmp short B11
B7: CMP AL,'N' ;Original order?
JNZ B8 ;Nope, try next one.
MOV SRTFLG,AL
jmp short B11
B8: CMP AL,'W' ;Wait when screen full?
JNZ B9 ;Nope, try next one.
MOV PSEFLG,AL ; djm
jmp short B11
B9: CMP AL,'M' ;Just show modified entries? djm
JNZ B10 ;Nope, try next one. djm
MOV MODFLG,AL ; djm
jmp short B11
B10: CMP AL,'H' ;Just show options? djm
JNZ B11 ;Nope, try next one djm
MOV OPTFLG,AL ; djm
B11: INC SI ;Point to next char
jmp B2 ;Test for another param.
B99: RET
GETARGS ENDP
SRCHDIR PROC NEAR ; do the actual directory search
MOV BYTE PTR old_ATTRIB,8 ;get volume label djm
mov al,DRVNBR
mov byte ptr old_DRVNBR,al
DOSCALL @SETDTA,DTA djm
DOSCALL @VOLLAB,XFCB ;get volume label djm
OR AL,AL ;found it? djm
JNZ C11 ;none found djm
MOV SI,OFFSET old_FILNAME ;source field djm
MOV DI,OFFSET VOLLOC ;put in vol label djm
MOV CX,11 ;length djm
CLD ;clear direction flag djm
REPZ MOVSB ;do it djm
c11: xor cx,cx
mov cl,ATTRIB
DOSCALL @SETDTA,DTA ;Set DTA for dir. search
mov ah,@srch1
mov dx,command_location
int 21h
C1: OR AL,AL
JZ C21 ;found djm
JMP C2 ;not found - quit looking djm
C21: mov si,offset FILNAME
MOV AL,[SI] ;get first byte of entry djm
CMP AL,'.' ;see if sub directory entry djm
JNZ C211 ;no - process
jmp C41
C211:
MOV BX,DIRLNK ;BX <- base of DIRBUF
LEA DI,[BX].NAM
MOV CX,13 ;13 bytes in the filename
CLD
mov al,' '
rep stosb ; fill the filename with blanks
lea di,[bx].sep
MOV AL,FILATR ;load file attributes djm
TEST AL,20h ;see if attr bit set djm
JZ C3 ;no djm
MOV BYTE PTR [DI],'+' ; djm
JMP SHORT C4 ; djm
C3: ; not modified - now see if /M set djm
CMP MODFLG,0 ;see if /M set djm
JNE C41 ;wasn't, so skip this entry djm
TEST AL,10H ;see if directory entry djm
JZ C31 ;no djm
MOV BYTE PTR [DI],'-' ;store a minus for dir djm
JMP SHORT C4 ; djm
C31: MOV BYTE PTR [DI],'.' ; Store a period
C4:
LEA DI,[BX].NAM ; start at the filename again
mov si,offset FILNAME
MOV CX,SIZE NAM
inc cx ; search 9 characters for the period, if needed
C22: lodsb
cmp al,0
je C4c ; quit if the end of the string
cmp al,'.'
je C23 ; found the period in the file name
stosb ;Move filename to DIRBUF
loop C22
C23:
lea di,[bx].ext
MOV CX,SIZE EXT
C4a: lodsb
cmp al,0
je C4c ; found the period in the file name
stosb ;Move ext to DIRBUF
loop C4a
C4c:
lea di,[bx].tme
MOV SI,OFFSET FILTIME
MOVSW ;Move time to DIRBUF
MOVSW ;Move date to DIRBUF
MOV SI,OFFSET FILSIZE
MOV AX,[SI] ;get number for size addition djm
ADD TOTL,AX ;add djm
MOVSW ;Move size to DIRBUF
MOV AX,[SI] ;get high order djm
ADC TOTH,AX ;add djm
MOVSW
ADD BX,SIZE DIRNTRY ;Point to next entry
MOV DIRLNK,BX ;Save ptr
INC NBRFILS ;Increment file count
C41: DOSCALL @SRCH2 ;Search for next file
JMP C1 ;Loop for next one
C2: RET
SRCHDIR ENDP
SRTDIRB PROC NEAR ;Sorts directory entries in DIRBUF
MOV DI,OFFSET DIRBUF ;Point to DIRBUF
D1: CMP DI,DIRLNK ;Are there anymore?
JNC D8 ;NO, exit
MOV SI,OFFSET C1LNK ;Start with column 1 ptr
D2: MOV BX,SI
MOV SI,[BX] ;SI<-ptr to next entry
OR SI,SI
JZ D7 ;if link=0
MOV AX,SI
MOV DX,DI
XOR CL,CL ;CL <- 0
CMP CL,SIZFLG
JNZ D5 ;If sort by size
CMP CL,DTEFLG
JNZ D4 ;If sort by date/time
CMP CL,EXTFLG
JNZ D3 ;If sort by ext
LEA SI,[SI].NAM
LEA DI,[DI].NAM
MOV CX,1+SIZE NAM+SIZE EXT ;# of bytes
JMP SHORT D6
D3: LEA SI,[SI].EXT ;Sort by extension
LEA DI,[DI].EXT
MOV CX,SIZE EXT ;# of bytes
JMP SHORT D6
D4: LEA SI,[SI].DTE ;Sort by date/time
LEA DI,[DI].DTE
MOV CX,2 ;# of words
STD
REPZ CMPSW
MOV DI,DX
MOV SI,AX
JBE D2
JMP SHORT D7
D5: LEA SI,[SI].SZH ;Sort by size
LEA DI,[DI].SZH
MOV CX,2 ;# of words
STD
REPZ CMPSW
MOV DI,DX
MOV SI,AX
JBE D2
JMP SHORT D7
D6: CLD ;Sort by name.ext
REPZ CMPSB
MOV DI,DX
MOV SI,AX
JBE D2
D7: MOV [DI],SI
MOV [BX],DI
ADD DI,SIZE DIRNTRY ;Point to next entry
JMP D1
D8: RET
SRTDIRB ENDP
; LNKDIRB - LINKS ENTRIES IN DIRBUF
LNKDIRB PROC NEAR ;LINK ENTRIES IN DIRBUF
MOV DI,OFFSET DIRBUF
MOV C1LNK,DI ;Point to 1st entry
MOV CX,NBRFILS ;Set loop counter
DEC CX
LNK1:
MOV BX,DI
ADD DI,SIZE DIRNTRY ;Offset to next entry
MOV [BX],DI ;Store ptr
LOOP LNK1 ;Link next entry
MOV [DI],CX ;Last ptr <- null
RET
LNKDIRB ENDP
; SPLTLST - SPLITS LINKED LIST IN HALF
SPLTLST PROC NEAR
MOV CX,NBRFILS ;Get # of entries
SAR CX,1 ; and divide by 2
JZ F2 ;if NBRFILS < 2
ADC CL,0 ;Account for odd #
MOV BX,OFFSET C1LNK
F1: MOV BX,[BX] ;Chain thru list to
LOOP F1 ; last row of column 1.
MOV AX,[BX] ;Get ptr to 1st row of col 2
MOV C2LNK,AX ; C2LNK <- R1,C2 ptr
MOV [BX],CX ;Last row of col 1 <- null
F2: RET
SPLTLST ENDP
GETFREE PROC NEAR ;cluster = allocation unit
MOV DL,DRVNBR ;Get drive #
PUSH DS ;Save DS
DOSCALL @DSKFSP ;get disk free space JYF
MUL BX ;AX (sectors/clustor) * BX (free cluJYF
MOV DX,AX ; JYF
MUL CX ;AX * CX (bytes/clustor) JYF
; JYF
POP DS ;Restore DS
MOV LOSIZE,AX ;Save the 32 bit
MOV HISIZE,DX ; binary free space
RET
GETFREE ENDP
PRTHDNG PROC NEAR
DOSCALL @GETDTE ; CX<-year, DH<-month, DL<-day
MOV AL,DH
AAM
XCHG AL,AH
OR D_MM,AX ;Fold into month
MOV AL,DL
AAM
XCHG AL,AH
OR D_DD,AX ;Fold into day
MOV AX,CX
SUB AX,1900
AAM
XCHG AL,AH
OR D_YY,AX ;Fold into year
DOSCALL @GETTME ; CH<-hours, CL<-minutes
MOV AL,CH ;AL<-binary hours
AAM ;Convert AL to two
XCHG AL,AH ; BCD digits in AX.
OR T_HH,AX ;Fold into hours
MOV AL,CL ;AL<-binary minutes
AAM ;Convert AL to two
XCHG AL,AH ; BCD digits in AX.
OR T_MM,AX ;Fold into minutes
cld ; make all moves forward
mov di,offset dirloc
mov si,offset command_line
cmp other_dir,2 ; are both drive & dir specified?
je G11
mov al,DRVNBR ; if drive & path weren't spec'd
add al,'@' ; put 'em into DIRLOC
stosb
mov al,':'
stosb
cmp other_dir,1 ; was only the dir specified?
je G11
MOV DL,DRVNBR ;set dl to current drive djm
MOV SI,OFFSET DIRWRK ;point to work area djm
DOSCALL @GETDIR ;get directory djm
MOV AL,[SI] ;get 1st char djm
CMP AL,0 ;see if no directory name djm
JE G11a ;this is root directory djm
mov al,'\'
stosb
jmp short G11
G11a:
MOV SI,OFFSET ROOT ;get * * ROOT * * djm
G11:
MOV CX,26 ; djm
REPZ MOVSB ; djm
mov si,offset HDNG1 ;Print main heading
call show_line
mov si,offset HDNG2 ;Print column 1 heading
call show_line
CMP WORD PTR C2LNK,0
JZ G2 ;If not 2 columns
mov si,offset SPACES-5 ;Print 5 spaces
call show_line
mov si,offset HDNG2 ;Print column 2 heading
call show_line
G2: mov si,offset CRLF ;Start a new line
call show_line
RET
PRTHDNG ENDP
PRTDRVR PROC NEAR ;Driver routine
MOV BX,C1LNK
OR BX,BX ;more to print?
JZ H2 ; no, return
MOV AX,[BX]
MOV C1LNK,AX
CALL PRTDTL ;print column one
MOV BX,C2LNK
OR BX,BX
JZ H1 ;If no column 2 entry
mov si,offset SPACES-5 ;print 5 spaces
call show_line
MOV AX,[BX]
MOV C2LNK,AX
CALL PRTDTL ;print column two
H1: mov si,offset CRLF
call show_line
CMP PSEFLG,0 ;Check for pause option
JZ PRTDRVR ;Nope, continue
DEC LINCNT ;Decrement line counter
JNZ PRTDRVR ;If page not full?
MOV LINCNT,LPERSCR-2 ;Reset to # lines/screen
mov si,offset PSEMSG ;Display pause message.
call show_line
MOV ah,0 ;Specify input function
int 67h ;Wait for key press
mov si,offset CRLF ;Set to new line
call show_line
JMP PRTDRVR ;Go do the next line
H2: RET
PRTDRVR ENDP
PRTDTL PROC NEAR ;Prints file.ext, size, date & time
MOV AL,[BX][0AH] ;get file.ext separator djm
CMP AL,'-' ;see if minus inserted djm
JNZ SHORT I0 ;not a Dir entry djm
MOV BYTE PTR [BX][0AH],' ' ;clear minus sign djm
OR DIRSW,1 ;set switch on djm
I0: MOV CX,1+SIZE NAM+SIZE EXT
SUB DI,DI ;DI <- 0
I1: mov al,[BX+DI].NAM
call show_char
INC DI ;point to next char.
LOOP I1 ;go do next char.
CMP DIRSW,1 ;see if this is directory entry djm
JNZ I11 ;no djm
mov si,offset SPACES-8 ;print 8 spaces instead of size djm
call show_line
JMP SHORT I12
I11: PUSH BX ;save entry base
MOV SI,[BX].SZL ;SI <- low size
MOV DI,[BX].SZH ;DI <- high size
CALL PRINTDD ;Print size
POP BX ;restore entry base
I12: mov si,offset SPACES-2 ;print 2 spaces
call show_line
MOV AX,[BX].DTE ;AX <- packed date
CALL PRTDTE
mov si,offset SPACES-2 ;print 2 spaces
call show_line
MOV AX,[BX].TME ;AX <- packed time
CALL PRTTME
CMP DIRSW,1 ;see if switch on djm
JNZ I2 ;no djm
MOV DIRSW,0 ;shut off switch djm
I2: RET
PRTDTL ENDP
PRINTDD PROC NEAR ;Prints a 32 bit integer in DI:SI
XOR AX,AX ;Zero out the
MOV BX,AX ; working
MOV BP,AX ; registers.
MOV CX,32 ;# bits of precision
J1: SHL SI,1
RCL DI,1
XCHG BP,AX
CALL J6
XCHG BP,AX
XCHG BX,AX
CALL J6
XCHG BX,AX
ADC AL,0
LOOP J1
MOV CX,1710H ;5904 ?
MOV AX,BX
CALL J2
MOV AX,BP
J2: PUSH AX
MOV DL,AH
CALL J3
POP DX
J3: MOV DH,DL
SHR DL,1 ;Move high
SHR DL,1 ; nibble to
SHR DL,1 ; the low
SHR DL,1 ; position.
CALL J4
MOV DL,DH
J4: AND DL,0FH ;Mask low nibble
JZ J5 ;If not zero
MOV CL,0
J5: DEC CH
AND CL,CH
OR DL,'0' ;Fold in ASCII zero
SUB DL,CL
push ax
mov al,dl
call show_char
pop ax
RET ;Exit to caller
PRINTDD ENDP
J6 PROC NEAR
ADC AL,AL
DAA
XCHG AL,AH
ADC AL,AL
DAA
XCHG AL,AH
RET
J6 ENDP
PRTDTE PROC NEAR ;Print packed date in AX as MM/DD/YY
OR AX,AX
JNZ K1 ;If date <> 0
mov si,offset SPACES-8 ;Print 8 spaces
call show_line
RET
K1: PUSH AX
AND AX,MASK P_MO ;Mask the month,
MOV CL,P_MO ; set shift count,
SHR AX,CL ; right justify, &
CALL PRTBCD ; print it.
mov al,'/'
call show_char
POP AX
PUSH AX
AND AX,MASK P_DY ;Mask the day &
CALL PRTBCD ; print it.
mov al,'/'
call show_char
POP AX
AND AX,MASK P_YR ;Mask the year,
MOV CL,P_YR ; set shift count,
SHR AX,CL ; right justify,
ADD AX,80 ; add in year bias, &
; print it.
call prtbcd
ret
PRTDTE ENDP
PRTBCD proc near
push ax
AAM ;Convert AL to BCD
OR AX,'00' ;Convert to ASCII
PUSH AX
mov al,AH ;High order digit
call show_char
POP AX
call show_char
pop ax
RET
PRTBCD ENDP
PRTTME PROC NEAR ;Print packed time in AX as HH:MM
OR AX,AX
JNZ L1
mov si,offset SPACES-5 ;Print 5 spaces
call show_line
RET
L1: PUSH AX
AND AX,MASK P_HR ;Mask the hours,
MOV CL,P_HR ; set shift count,
SHR AX,CL ; right justify, &
CALL PRTBCD ; print it.
mov al,':'
call show_char
POP AX
AND AX,MASK P_MI ;Mask the minutes,
MOV CL,P_MI ; set shift count,
SHR AX,CL ; right justify, &
CALL PRTBCD ; print it.
RET
PRTTME ENDP
PRTNFLS PROC NEAR ;print number of files
MOV SI,NBRFILS ;get # of files
XOR DI,DI ;zero high order
CALL PRINTDD ;Print # of files
mov si,offset HDNG3
call show_line
MOV SI,TOTL ;set up total for print djm
MOV DI,TOTH ; djm
CALL PRINTDD ;print total space used by dir djm
mov si,offset HDNG5 ; djm
call show_line
MOV SI,LOSIZE ;free space djm
MOV DI,HISIZE ; djm
CALL PRINTDD ;print free space djm
mov si,offset HDNG6 ; djm
call show_line
RET
PRTNFLS ENDP
;
; storage for directory entries
; please note - 256 entries is more than enough for anything
; on my system -- but if you've got directories with more entries
; please increase the space.
;
EVEN
DIRBUF DIRNTRY 256 dup(<>) ;Buffer for directory entries
;
; storage for a local stack
dw 150 dup(0)
stacktop label word
;
; This procedure initializes the new keyboard interupt vectors
;
bad_intr db 'MDIR cannot be installed -- its interrupt'
db ' vectors are already in use.$'
SWAP_VECTORS proc near
push ds ;Set up the
xor ax,ax ; stack for a
push ax ; return to DOS.
push cs
pop ds ; set up DS
push cs
pop es ; and ES to point to this section
mov di,80h ; read the command line
mov cl,es:[di]
xor ch,ch ; clear the high byte
cmp cl,2
jb one_monitor ; if no command line
mov al,' ' ; Set up to scan for first non-blank
inc di ; Set DI to PC-DOS parameter pointer
repe scasb ; Scan while blanks
jz one_monitor ; if we've scanned everything
mov al,es:[di-1] ; get the first non-blank byte
cmp al,'2' ; are there two monitors?
jne one_monitor
mov two_screens,1 ; two monitors specified, so set the flag
mov permpse,0 ; don't pause unless told to do so
one_monitor:
mov ax,0
mov es,ax ;Clear esp. for Dos 3.0 bug
push es ; save es
mov ah,35h ; get the address if Int 67h
mov al,67h
int 21h
mov ax,es
cmp ax,0
pop es ; restore the 0'd ES
jne bad_exit ;get out if the int is already used
mov ah,35h ; get the address of the keyboard interrupt
mov al,16h ; keyboard function
int 21h ; get interrupt vector
mov word ptr ROM_KB_INT,bx ; save the offset
mov word ptr ROM_KB_INT[2],es ; and the segment
mov ah,25h ; reset the keyboard interrupt
mov al,16h
push cs
pop ds ; DS:DX point to this routine
mov dx,offset MDIR_INT
int 21h ; set interrupt vector
mov ah,25h ; and reset Int 67h to point to the
mov al,67h ; old interrupt code
mov dx, word ptr ROM_KB_INT
mov bx, word ptr ROM_KB_INT[2]
mov ds,bx ; DS:DX point to the new interrupt
int 21h ; set interrupt vector
int 11h ; get the equipment flag
mov bx,ax ; save a copy of the flags
and bl,1 ; are there any floppy disk drives?
cmp bl,1
jne stay_res
and al,11000000b ; mask the count bits
mov cl,6
shr al,cl ; get the count
inc al ; and set it so that 1 = 1 drive
mov cs:MAXDRIVE,al ; and save the number of floppy drives
; for future reference
stay_res:
mov dx,offset bad_intr ; End of new resident program
int 27h ; Terminate but stay resident
bad_exit: ; whoops, something ain't kosher, so
mov ah,9 ; print error message
mov dx,offset bad_intr
int 21h
ret ; return to DOS
SWAP_VECTORS endp
CODE_SEG ends
end BEGIN
;