Category : Assembly Language Source Code
Archive   : MISC_ASM.ZIP
Filename : LDIR.ASM

Output of file : LDIR.ASM contained in archive : MISC_ASM.ZIP
page 74,132
title --- ldir - list directory -

; LDIR (c) Copyright Vernon D. Buerg 1985-1991

dtantry struc ; DTA entry returned by DOS
dtarsvd db 21 dup (0) ; reserved
dtaattr db 0 ; attribute
dtatime dw 0 ; update time
dtadate dw 0 ; update date
dtasize dw 0,0 ; size bytes (lo,hi)
dtaname db 12 dup (' ') ; name and ext
db 0,13,10,255 ; stopper and print
dtantry ends

argntry struc ; Search arguments
argdriv db 0,':' ; drive
argpath db '\' ; path delimiter
argname db 64 dup (0),255 ; path,file,ext
argntry ends

tblntry struc ; Table Entries
tblattr db 0 ; attribute
tblpath db 21 dup (0) ; path name(s)
tblname db 8 dup (' ') ; file name
tbldot db ' ' ; delimiter
tblext db 3 dup (' ') ; extension
tblsize db ' 0000000 ' ; File size
tbldate db '80-01/01 ' ; Date
tbltime db ' 0:00 ' ; Time
tblfatr db 3 dup (' ') ; File attributes
tblctl db 13,10,255 ; print control chars
tblntry ends

filntry struc ; List of files in table
filsub db 0 ; -index to subdirectory name
filattr db 0 ; -file attributes
filtime dw 0 ; -time stamp
fildate dw 0 ; -date stamp
filsize dw 0,0 ; -file size
filname db 12 dup ('?') ; -asciiz file name
filstop db ? ; -asciiz stopper
filntry ends

bios segment at 40h ; dos data area
org 84h ;
ega_row label byte ; rows on screen
bios ends

save macro reglist
irp reg,
push reg ; save register

return macro reglist
irp reg,
pop reg ; restore register
ret ; return to caller

cseg segment public para 'CODE'
assume cs:cseg, ds:cseg, es:nothing
org 100h

ldir proc far
jmp start

; Usage information, display panel

db bs,bs,bs,' ',cr,lf ; in case TYPEd

help db cr,lf,tab,tab,' -- LDIR Version 4.4 --- 25 Mar 91 --'
db cr,lf,tab,tab,' (c) Copyright Vernon D. Buerg 1985-91'
db cr,lf
db cr,lf,tab,tab,tab,' Command syntax:'
db cr,lf
db cr,lf,tab,tab,'LDIR [d:][\path[fname[.ext]]] /?.../?'
db cr,lf,tab,tab
db cr,lf,tab,tab,' /A include Attributes'
db cr,lf,tab,tab,' /B Brief headings'
db cr,lf,tab,tab,' /C Clear screen first'
db cr,lf,tab,tab,' /D sort by Date'
db cr,lf,tab,tab,' /F sort by Filename (default)'
db cr,lf,tab,tab,' /H include Hidden files'
db cr,lf,tab,tab,' /M only Modified files'
db cr,lf,tab,tab,' /N No sorting'
db cr,lf,tab,tab,' /P include all Paths'
db cr,lf,tab,tab,' /S sort by Size'
db cr,lf,tab,tab,' /V Verbose headings'
db cr,lf,tab,tab,' /W Wait after screen full'
db cr,lf,tab,tab,' /X sort by eXtension'
db cr,lf,tab,tab,' /? display usage syntax',Stopper
db stopper,26

; Data Areas, Constants, Etc.

dta_len equ size dtantry ; DTA length
arg_len equ size argntry ; Argument length
tbl_len equ size tblntry ; Disk record entry
fil_len equ size filntry ; File description entry

tblpara equ tbl_len/16 ; paragraphs in each table entry

depth equ 3 ; Maximum sub-DIR nest level
tab equ 9 ; A tabbie
lf equ 10 ; Line feed
cr equ 13 ; Carriage return
stopper equ 255 ; Ends print strings
bs equ 8 ; Backspace

curdsk equ 19h ;Get current disk
setdta equ 1ah ;Set data transfer area
dskspc equ 36h ;Get disk free space
chdir equ 3bh ;Change directory
write equ 40h ;Write to a file handle
getpath equ 47h ;Get current directory

stackx dw 0 ; Entry stack pointer
dirmask db 0 ; Directory flags mask
errlvl db 0 ; DOS return code
_attr db 7 ; Clear attribute
_page db 0 ; Video page
_rows db 0 ; Rows on screen

flags db byname ; Command switches
byattr equ 1 ; -attributes included
byhide equ 2 ; -want hidden files
byclear equ 4 ; -clear screen
bydate equ 8 ; -sort by date/time
byext equ 10h ; -sort by extension
byname equ 40h ; -sort by name
bysize equ 80h ; -sort by size

flags2 db 0 ; More switches
bymod equ 01h ; -modified files only
bywait equ 02h ; -wait when screen full
bybrief equ 4 ; -four up
bypath equ 20h ; -all paths
byv equ 40h ; -verbose headings

date record yr:7,mo:4,dy:5 ; Packed date
time record hour:5,min:6,sec:5 ; Packed time

anyname db '\????????.???',0,stopper ;Global filename.ext
subdir db '-Dir'

count dw 0 ; Number of files
numdir dw 0 ; Number of table entries
maxdir dw 0 ; Maximum table entries
nxtdir dw 0 ; Offset to next entry
segdir dw 0 ; Segment addr of of gotten table
numbyte dw 0,0 ;Total bytes used
linecnt db 0 ;Line counter for /W

ddptr dw 0

; Headings and titles

titlea db 'List DIRectory Volume: '
volname db 11 dup (' '),11 dup (' ')
month db 'mm/'
day db 'dd/'
year db 'yy '
hours db 'hh:'
mins db 'mm:'
secs db 'ss',cr,lf,stopper

more db '... more',stopper
backsp db 8 dup (8),stopper ; backspace over 'more'

titleb db tab,tab,tab,tab,' ' ; Command parameters
titles db 64 dup (0),stopper ; Current directory

titlec db cr,lf,'Filename Ext Bytes -Last Change- '
titled db 'Filename Ext Bytes -Last Change-'
newline db lf,cr,stopper

nrmsg db cr,cr,' ' ; Ending message
nrbytes db ' bytes in'
nrfiles db ' File(s); '
db ' '
nrsize db ' bytes free.',stopper

extfcb db 255,0,0,0,0,0 ; Extended FCB to get label
db 8 ; Attribute
drivenr db 0,11 dup('?') ; Drive number
db 2 dup(0) ; Current block number
db 3 dup(0) ; Logical record size
db 20 dup(0) ; File size

temp db 0 ; Sort exchange area
origdr db 'x:' ; Original drive
origdir db '\',63 dup (0) ; and path
origptr dw origdir ; End of orig path name

rootdir db 'x:\',0 ; To get vol label
olddate db 8 dup (0) ;
drptr dw offset parmdr ;

model tblntry <> ; Model print line
; Set default drive and path

mov sp,offset local_stack_end ; Use local stack
mov word ptr stackx,sp ; Save stack ptr for exiting
mov ah,8 ; Get monitor stuff
int 10h ;
mov _page,0 ; -video page
mov _attr,ah ; -current attribute

push es ; set dos data area
mov ax,bios ; segment address
mov es,ax ;
mov al,byte ptr es:ega_row ; dos rows on screen
mov ah,24 ; default max rows
or al,al ; is row value ok?
jz start1 ; no, use default
mov ah,al ; yes,
mov byte ptr _rows,ah ; set max rows on screen
pop es ;

call switchs ; Get program options

mov ah,13 ; Reset diskettes
int 21h ;

mov ah,curdsk ; Get current disk
int 21h ;
add al,'A' ;
mov origdr,al ; Save original drive letter
mov rootdir,al ; for reading vol label
mov parmdr,al ;

mov dx,offset dta ; Set Data Transfer Area
mov ah,setdta ;
int 21h ;

call getparm ; Get desired dr:path in 'parmdir'

call getvol ; Get vol name, current dir in 'origdir'

call setarg ; Set search argument

call alloc ; Allocate table for directory

call clock ; Date/time to heading

call getdir ; Read the directory

test flags,bydate+byext+byname+bysize ; Any sort options? ;4.4
jz nosort ; no, display fifo dir
call sort ; Sort directory table

call print ; Display the entries

mov ax,count ; Number of files
sub dx,dx ;
mov si,offset nrfiles ;
call format ;

mov dx,numbyte ; Total bytes used
mov ax,numbyte+2 ;
mov si,offset nrbytes ; target field
call formatc ; Make pretty
mov dx,offset nrmsg ; Display summary stats

exit: mov sp,cs:stackx ; Insure exiting stack
call prints ; Display final message

done: mov sp,cs:stackx ; Insure exiting stack
mov al,errlvl ; Return to system
mov ah,4ch ; via EXIT with error level
int 21h ;

ldir endp

; Set options from command line

switchs proc near
mov si,82h ; Command tail
mov dh,flags ; Default switches
mov dl,flags2
sub cx,cx
or cl,byte ptr -2[si] ; test parm length
jz switch_exit ; none, return as-is

sw1: lodsb ; Scan for switch
cmp al,'/'
loopne sw1
or cx,cx ; found one?
jz switch_exit
mov byte ptr -1[si],cr ; Stop string here
jmp short sw2a

mov flags,dh ; Store new switches
mov flags2,dl
test dh,byclear ; Want clear screen?
jz swx0 ; no, skip next
call cls ; yes

swx0: mov al,dirmask ; Current directory attribute mask
test flags,byhide ; include hidden files
jz swx1
or al,2
swx1: test flags,byattr ; include display of attributes?
jz swx2
or al,7
swx2: test flags2,bypath ; include sub-directories?
jz swx3
or al,16
swx3: mov byte ptr dirmask,al ; Update dir search criteria

sw2: lodsb
cmp al,'/' ; Another switch?
loopne sw2
jcxz switch_exit

sw2a: lodsb ; yes, get letter following
dec cx
jle sw3 ; missing switch

sw3: cmp al,'?' ; Help?
jne sw4
mov dx,offset help
jmp exit

sw4: and al,0dfh ; Make option uppercase
cmp al,'A' ; Attributes?
jne sw5
or dh,byattr
sw5: cmp al,'B' ; Brief?
jne sw6
or dl,bybrief
sw6: cmp al,'C' ; Clear?
jne sw7
or dh,byclear
sw7: cmp al,'D' ; Date?
jne sw8
or dh,bydate
sw8: cmp al,'X' ; Ext?
jne sw9
or dh,byext
sw9: cmp al,'P' ; Paths?
jne sw10
or dl,bypath
sw10: cmp al,'S' ; Size?
jne sw11
or dh,bysize
sw11: cmp al,'H' ; Hidden?
jne sw12
or dh,byhide
sw12: cmp al,'M' ; Modified only
jne sw12b
or dl,bymod
sw12b: cmp al,'W' ; Wait when screen fills?
jne sw12c
or dl,bywait
sw12c: cmp al,'F' ; Sort by filename?
jne sw12d
or dh,byname
sw12d: cmp al,'N' ; No sorting?
jne sw13
and dh,0ffh-byname-byext-bysize-bydate

sw13: cmp al,'B' ; Brief headings?
jne sw14 ;
or flags2,byv ;
jmp sw2 ; Try for another option

switchs endp
; Copy command parameters

getparm proc near
mov si,82h ; Command tail
mov di,offset parmdir ; goes after d:\
sub cx,cx ;
or cl,byte ptr -2[si] ; any parmeters?
jz parm9 ; no, use defaults

parm0: cmp byte ptr 1[si],':' ; Drive specified?
jne parm1 ; no
mov di,offset parmdr ; yes, replace drive letter

parm1: lodsb ; Skip leading blanks
cmp al,' ' ;
jne parm3 ;
loope parm1 ;
jcxz parm9 ;

parm2: lodsb ; Copy d:\path\fname.ext
parm3: cmp al,cr ; end of string?
je parm9 ;
cmp al,' ' ; end of operand?
jbe parm9 ;
cmp al,',' ;
je parm9 ;
stosb ;
loop parm2 ;

parm9: and byte ptr parmdr,0dfh ; Upper case drive parm
mov drptr,di ; Save ptr to parm end
mov al,0 ; Insure asciiz
stosb ;
mov al,parmdr ;
mov origdr,al ;
mov rootdir,al ;
ret ;
getparm endp
; Get volume label and disk free space

getvol proc near
mov dl,parmdr ; Get drive letter
sub dl,64 ; and make it a number
mov drivenr,dl ;
mov si,offset origdir+1 ; Save current path name
mov ah,getpath ;
int 21h ;

mov al,0 ; Get end of path name
mov di,offset origdir ;
mov cx,67 ;
repne scasb ;
sub di,2 ;
mov origptr,di ;

cmp origdir+1,0 ; Already in root?
je getvl3 ; yes, no chdir needed
inc origptr ;
mov dx,offset rootdir ; no, point to root directory
mov ah,chdir ;
int 21h ;
jc getvl9 ;

getvl3: mov dx,offset extfcb ; Search for volume entry
mov ah,11h ;
int 21h ;

or al,al ; Any found?
jnz getvl4 ; no, tough
mov cx,11 ; yes, copy it to heading
mov si,offset dta+8 ;
mov di,offset volname ;
repz movsb ;

getvl4: cmp origdir+1,0 ; Need to restore curdir?
je getvl9 ;
mov dx,offset origdr ; Back to current dir
mov ah,chdir ;
int 21h ;

getvl9: ; Get disk free space
mov dl,parmdr ; Current drive letter
sub dl,64 ; as a number
mov ah,dskspc ; Get free space
int 21h ;
cmp ax,0ffffh ; Valid?
je getvl10 ; no, skip it
mul cx ; Bytes per cluster
mul bx ; Total free
mov si,offset nrsize ; Format size
call formatc ; with commas

ret ;
getvol endp ;
; Set search criteria

setarg proc near
set1: mov bp,offset dta ; First DTA
mov bx,offset search ; Search arument entries

mov ax,word ptr parmdr ; Set search drive
lea di,[bx].argdriv ;
stosw ;

; parameter is possibly a filespec

set2: cmp byte ptr parmdir,'\' ; path requested?
je set8 ; yes, more than a filespec
mov cx,origptr ; no, set search path
mov si,offset origdr+2 ; from original path
sub cx,si ;
jcxz set2a ; In a subdir?
rep movsb ;
mov al,'\' ; Add filespec delimiter
stosb ;

set2a: mov si,offset parmdir ; Copy filespec
mov cx,drptr ; to search criteria
sub cx,si ;
jcxz set5 ; None, append global filespec
rep movsb ;
jmp set7 ; Done

; parameter is possibly a path\filespec

set8: mov dx,offset parmdr ; Requested d:\path\filespec
mov ah,chdir ;
int 21h ; Is parm a valid path name?
jc set4 ; no, have d:\path\filespec

set8a: mov dx,offset origdr ; Restore path
mov ah,chdir ;
int 21h ;

mov si,offset parmdir ; Set search d:\path
mov cx,drptr ; from command parameter
sub cx,si ;
jcxz set5 ;
rep movsb ;
jmp set5 ; Append global filespec

set4: mov si,offset parmdir ; Set search d:\path
mov cx,drptr ; from command parameter
sub cx,si ;
set4a: jcxz set5 ;
rep movsb ;
jmp set7 ; Done

; append global filespec to search criteria

set5: mov si,offset anyname ; Add global search arg
cmp byte ptr -1[di],'\' ; Already have delimiter?
jne set6 ;
dec di ; yes, overlay it

set6: mov cx,15 ; Length of global filespec
push di ; Save current end pointer
rep movsb ;
pop di ; Restore work reg
jmp set9 ;

set7: mov al,0 ; Append ASCIIZ stopper
stosb ;

set9: lea si,[bx].argdriv ; Copy d:\path\filespec
mov cx,di ;
sub cx,si ;
mov di,offset titles ; to titles
rep movsb ;
mov byte ptr [di],stopper ; Add print stopper

set10: ret ; Back to caller

setarg endp
; Obtain directory table

alloc proc near
push bx ; save registers
mov bx,pgmsize ; size of program module
mov ah,4ah ; modify memory
int 21h ;
mov bx,-1 ; ask for all remaining memory
mov ah,48h ; allocate memory
int 21h ;
jc alloc1 ; get what there is

mov segdir,ax ; segment addr of table
mov nxtdir,0 ; offset to first entry

shr bx,1 ; change number of paragraphs
shr bx,1 ; to 64-byte entries
mov maxdir,bx ; maximum table count
pop bx ; restore registers
ret ;
alloc endp

; Build table of directory entries

getdir proc near
push bp ; Ptr to DTA
push bx ; Ptr to search are

; Set DTA for current nesting level
mov dx,bp ; Data transfer area
mov ah,setdta ; Set local DTA
int 21h

; Set search criteria for this level
mov dx,bx ; Search criteria
sub cx,cx ; Directory options
mov cl,dirmask
mov ah,4eh ; Find first matching entry
int 21h

; Examine directory entry just returned
get1: or al,al
jnz gotdir ; Not found, quit looking.
cmp byte ptr [bp].dtaattr,10h
jne get3 ; Is it a sub-dir?
cmp byte ptr [bp].dtaname,'.'
je get4 ; May be entry

call addfile ; Add directory entry to table

; Build parms for sub-dir search
lea dx,[bp].dtaname ; Save ptr to found name
lea si,[bx].argdriv ; Point to current arg
add bp,dta_len ; Next DTA
add bx,arg_len ; Next search arg

; Copy previous arg as next search arg
mov cx,64 ; Maximum length
lea di,[bx].argdriv ; Point to new search arg
get6: lodsb ;
cmp al,'?' ; Used global name?
je get9 ; yes, single nest
cmp al,0 ; End of dir name?
je get5 ; yes, append wild cards
stosb ;
loop get6 ; Continue copying

; Add sub-dir name to search arg
get9: mov si,dx ; Saved ptr to found name
get8: lodsb ;
cmp al,0 ; End of DIR name?
je get5 ; yes, append wild cards
stosb ; no, add to arg
loop get8 ; Continue copying fname

get5: mov si,offset anyname ; Append wild cards
rep movsb ;

call getdir ; Search the sub-dir
sub bx,arg_len ; restore arg
sub bp,dta_len ; and DTA

; Restore DTA to find next matching entry
mov dx,bp ; Data transfer area
mov ah,setdta ; Set DTA
int 21h ;
jmp short get4 ;

get3: call addfile ; Add the entry

get4: mov cx,12 ; Clear found name
mov al,' ' ;
lea di,[bp].dtaname ; Point to file name area
rep stosb ;

mov ah,4fh ; Search for next file
mov dx,bp ;
int 21h ;
jmp get1 ; Loop for next one

gotdir: pop bx ; Restore arg
pop bp ; and DTA
ret ; Return to caller
getdir endp ;
; Add a directory entry to table

addfile proc near
save ; Save registers

mov cx,tbl_len ; Initialize table entry
mov si,offset model ;
mov di,offset pline ;
rep movsb ;

mov al,[bp].dtaattr ; Copy file attributes
mov pline.tblattr,al ;
test flags2,bymod ; Just modified files?
jz addfile1 ; no, add all
test al,10h ; yes, pass subdirs
jnz addfile1 ;
test al,20h ; is it modified tho?
jnz addfile1 ; yes, add the entry
jmp addfile11 ; no, exit

call getdate ; Format date
call gettime ; time
call getsize ; bytes

lea si,[bp].dtaname ; Copy file name
lea di,pline.tblname ;
mov cx,12 ;
lodsb ;
cmp al,0 ;
je addfile5 ;
cmp al,'.' ; separate extension
je addfile3 ;
stosb ;
loop addfile2 ;
jcxz addfile5 ;
lea di,pline.tblname+8 ;
stosb ;
lodsb ;
cmp al,0 ;
je addfile5 ;
loop addfile4 ;

lea di,pline.tblpath ; Copy path name
lea si,[bx].argname ;
mov cx,size tblpath ;
cmp byte ptr 1[si],'?' ; Wildcard part?
je addfile7 ; yes, have name
lodsb ;
stosb ;
loop addfile6 ;

lea si,pline.tblname ;
test pline.tblattr,10h ; Subdirectory?
jnz addfile8 ; yes, copy path name
jcxz addfile10 ; no, pad with blanks
mov al,' ' ;
rep stosb ;
jmp addfile10 ;

cmp cl,12 ; Max subdir name length
jbe addfile9 ; to be copied
mov cl,12 ;
rep movsb ;

mov cx,numdir ; Number of table entries
cmp cx,maxdir ; is table full?
jae addfile11 ; yes, skip it
push es ; no, add to table
mov ax,word ptr segdir ; Segment addr of table
add ax,nxtdir ; plus next entry offset
sub di,di ;
mov si,offset pline ; copy table stuff
mov cx,tbl_len ;
mov es,ax ; Set target segment
rep movsb ;
pop es ;

inc numdir ; Incr entry count
add nxtdir,tblpara ; Bump offset for next table entry

return ; restore registers
addfile endp
; Print file information

print proc near
cmp numdir,1 ; Just one file?
ja printt ; no, two up heading
mov word ptr titled,0a0dh ;
mov titled+2,stopper ;

test flags2,byv ; Want headings?
jnz printv ; no
add linecnt,3 ; yes
mov dx,offset titlea ; Top titles
call prints ;
mov dx,offset titleb ; Subdir name
call prints ;
mov dx,offset titlec ; Headings
call prints ;
mov ax,cs ; Set extra seg
mov es,ax ; locally

sub ax,ax ; Offset to first table entry
mov nxtdir,ax ; as current entry
mov ax,numdir ; Compute offset
inc ax ; to second half
shr ax,1 ;
mov cl,2 ; Times 64 (4 paras each)
shl ax,cl ;
mov cx,numdir ; Number of entries
or cx,cx ; Even number of entries?
jz print7 ; yes, all set
inc cx ; no, just one
shr cx,1 ; Set half of count

call print0 ; Left side
push [nxtdir] ;
add nxtdir,ax ;
call print0 ; Right side
pop [nxtdir] ;

add nxtdir,tblpara ; Point to next entry

test flags2,bywait ; Wait for screen full?
jz printw1 ; no, continue
inc linecnt ; yes, bump line count
mov dl,_rows ; rows available on screen
cmp linecnt,dl ; Full now?
jb printw1 ; no, continue
call waitkey ; yes, get a key

loop print_next ; continue for all entries
ret ; done, return
print endp ;

print0 proc near
save ; Save registers

push ds ; copy table entry to print line
mov cx,tbl_len ; length of table entry
sub si,si ; offset to next entry
mov di,offset pline ; offset to print line
mov ax,word ptr segdir ; Segment addr for table
add ax,nxtdir ; plus paras offset
mov ds,ax ; as source segment
rep movsb ; for copy
pop ds ;

inc count ; Number of files
mov ax,count ;
cmp ax,numdir ; Done em all?
jbe print1 ; no, display this one
dec count ; yes,
jmp print9 ; done, return

mov cl,byte ptr pline.tblattr
lea di,byte ptr pline.tblfatr

test cl,32 ; Archived?
jnz print2 ;
mov al,'A' ;
stosb ;

print2: test cl,4 ; System?
jz print3 ;
mov al,'S' ;
stosb ;

print3: test cl,2 ; Hidden?
jz print4 ;
mov al,'H' ;
stosb ;

print4: test cl,1 ; Read only?
jz print5 ;
mov al,'R' ;
stosb ;

print5: test cl,10h ; Sub directory?
jz print5a ; no
lea di,pline.tblfatr-1 ; yes, special display
mov si,offset subdir ;
mov cx,4 ;
rep movsb ; for copying

test flags2,bypath ; Doing all paths?
jz print6 ;
cmp pline.tblpath+1,'?' ; Nested entry?
je print6 ; no, as-is
mov pline.tblfatr-1,'-' ; yes, flag it in display

print6: lea si,pline.tbldate ; Reformat date
mov di,offset olddate ; for copying
mov cx,8 ;
rep movsb ;

lea di,pline.tbldate ; Format date
mov ax,word ptr olddate+3 ;
stosw ;
mov al,"/" ;
stosb ;
mov ax,word ptr olddate+6 ;
stosw ;
mov al,"/" ;
stosb ;
mov ax,word ptr olddate ;
stosw ;

cmp pline.tblext,' ' ; Any extension?
jne print8 ; yes, leave the dot
mov pline.tblext-1,' ' ; no, rid it

print8: lea dx,pline.tblname ;
mov byte ptr pline.tblctl,' '
mov byte ptr pline.tblctl+1,stopper
mov byte ptr nrmsg+1,lf ;
test count,1 ; Right side?
jnz print8a ;
mov byte ptr nrmsg+1,cr ;
mov word ptr pline.tblctl,0a0dh
call prints ; Display an entry

return ; Restore registers
print0 endp

; Pause at end of screen for any key

waitkey proc near
save ; save work regs

mov linecnt,0 ; reset counter
mov ah,2 ; Set cursor position
mov dl,0 ; col 72
mov dh,_rows ; last row
;; add dh,2 ; adjust for heading
sub bx,bx ;
int 10h ;

mov dx,offset more ; ask for more
call prints ;

mov ah,0 ; wait for a key
int 16h ;

mov dx,offset backsp ; backspace over 'more...'
call prints ;

test flags,byclear ; Clear screen each time?
jz waitkeyc ; no
call cls ; Clear screen
test flags2,byv ; need headings again?
jnz waitkeyx ; no
add linecnt,3 ; yes
mov dx,offset titlea ; Top titles
call prints ;
mov dx,offset titleb ; Subdir name
call prints ;
mov dx,offset titlec ; Headings
call prints ;

return ; restore registers
waitkey endp
; Format the date

getdate proc near ;Format the date
mov ax,word ptr [bp].dtadate
mov di,offset pline.tbldate
or ax,ax ;Is it zero?
jz gotdate
push ax ;Save date
and ax,mask yr ;Get year part
mov cl,yr ;Bits to shift
call cnvrt
or al,'8' ;Adjust for base year
mov al,'-'

pop ax ;Get the date back
push ax ;Save it
and ax,mask mo ;Get month part
mov cl,mo ;Bits to shift
call cnvrt2
mov al,'/'

pop ax ;Get the date back
and ax,mask dy ;Get day part
mov cl,dy ;Bits to shift
call cnvrt
getdate endp

; Format the time

gettime proc near ; Format the date
mov ax,word ptr [bp].dtatime;
lea di,pline.tbltime ;
or ax,ax ; It is zero?
jz gottime ;
push ax ; Save date
and ax,mask hour ; Get hour part
mov cl,hour ; Bits to shift
shr ax,cl ;
call cnvrt1 ;
stosw ;
mov al,':' ;
stosb ;

gt3: pop ax ; Get the time back
and ax,mask min ; Get min part
mov cl,min ; Bits to shift
call cnvrt ;
stosw ;
ret ;
gettime endp

cnvrt2 proc near ; Convert to ASCII
call cnvrt ;
cmp al,'0' ; Suppress leading zero
jne cnvrtd ;
mov al,' ' ;
ret ;

cnvrt: shr ax,cl ;
cnvrt1: aam ; Make AL into BCD
or ax,'00' ; and to ASCII
xchg al,ah ;
cnvrtd: ret ;
cnvrt2 endp ;
; Format the size

getsize proc near
save ; Ptr to Dta entry
mov ax,word ptr [bp].dtasize;
add numbyte+2,ax ;
mov dx,word ptr [bp].dtasize+2
adc numbyte,dx ;
lea si,pline.tblsize ; Target offset
call format ; Format double word
return ;
getsize endp

; Format ASCII numbers from binary

format proc near ; Formats a 32 bit integer in DX:AX
save ; to DS:SI
mov ddptr,si ; addr of target field
mov di,dx ; subroutine uses di:si
mov si,ax
call printdd

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
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
sub cl,cl
j5: dec ch
and cl,ch
or dl,'0' ;fold in ascii zero
sub dl,cl
mov bx,ddptr
mov [bx],dl ;ptr to next target field
inc ddptr

j6: adc al,al
xchg al,ah
adc al,al
xchg al,ah
format endp

; Binary to ASCII numbers with commas
; DX:AX has value to convert
; SI points to target area, 11-bytes

formatc proc near ;
push si ; Save parameters
mov bx,si ;
fs1: mov cx,10000 ; Get 10K
div cx ;
push ax ;
mov ax,dx ;
sub dx,dx ;
mov si,bx ; Point to msg
call format ; Rightmost 4 digits

fs1a: pop ax ; get 10k
sub dx,dx ;
or ax,ax ;
jz fs1x ; none left
or word ptr 3[bx],'00' ;
fs1b: mov cx,word ptr 3[bx] ; insert a comma
mov byte ptr 4[bx],',' ;
mov word ptr 2[bx],cx ;
mov cx,1000 ; compute 10m
div cx ;
fs1c: push ax ; save 10m
mov ax,dx ; copy 10k
sub dx,dx ;
lea si,-5[bx] ;
call format ; middle 3 digits
cmp byte ptr [bx],' ' ; millions?
je fs1d ;
mov cx,word ptr -1[bx] ; insert a comma
mov byte ptr [bx],',' ;
mov word ptr -2[bx],cx ;
or word ptr 1[bx],'00' ;

fs1d: pop ax ; get 10m
sub dx,dx ;
or ax,ax ;
jz fs1x ; none left
lea si,-9[bx] ;
call format ;

fs1f: cmp ax,9 ; need a zero?
jbe fs1x ; no
or word ptr -3[bx],'00' ;

fs1x: pop si ; Target

sub si,9 ; Point to first digit
mov cx,16 ; Maximum length
fs1y: lodsb ; Have non-zero?
cmp al,'0' ;
ja fs1z ; yes, insure readable
loop fs1y ;
jcxz fs1exit ;
cmp byte ptr [si],',' ;
je fs1w ;
or byte ptr [si],'0' ;
inc si ;
loop fs1z ;
ret ;
formatc endp

; Print String like INT 21H function 9

prints proc near ; DX has offset to string
save ; ending in char x'FF'
mov si,dx ; Ptr to string text
sub cx,cx ; Overall text length
ps1: lodsb
cmp al,stopper ; Ending hex FF?
je ps9
inc cx
jmp short ps1

mov bx,1 ; Standard output device
mov ah,40h ; to write to
int 21h

return ; Recover registers
prints endp

cls proc near ; Clear screen

mov ax,600h ; Scroll all lines
sub cx,cx ; upper left
mov dx,184fh ; lower right
mov bl,_page ; video page
mov bh,_attr ; attribute
int 10h ; Video I/O

mov bl,_attr ; Set cursor position
mov bh,_page
sub dx,dx ; to 1,1
mov ah,2
int 10h

return ; return to caller
cls endp

; Format current date and time

clock proc near
save ; save work regs

mov ah,2ah ;Get date
int 21h
sub cx,1900 ; last two digits
mov ax,cx ;Make readable
call cnvrt1 ;Convert to ASCII
mov word ptr year,ax
xchg al,dh ;Get month
call cnvrt1 ;Convert to ASCII
mov word ptr month,ax
xchg al,dl ;Get day
call cnvrt1 ;Convert to ASCII
mov word ptr day,ax

mov ah,2ch ;Get time
int 21h
xchg al,ch ;Get hours
call cnvrt1 ;Convert to ASCII
mov word ptr hours,ax
xchg al,cl ;Get minutes
call cnvrt1 ;Convert to ASCII
mov word ptr mins,ax
xchg al,dh ;Get seconds
call cnvrt1 ;Convert to ASCII
mov word ptr secs,ax

return ; return to caller
clock endp

; Shell-Metzger Sort of 64-byte table records

; Variables used for sort subroutine

numrec dw 0 ; Number of entries
loc dw 0
index1 dw 0
incr dw 0
limit dw 0
index2 dw 0
ptr1 dw 0 ;Offset to record Index1
ptr2 dw 0 ;Offset to record Index2

keyptr dw 0 ;Offset to key
keylen dw 0 ;Length of key
base dw 0 ;Seg addr of array

sort proc near
push ds ; Save seg regs
push es

; Set sort options

sub bx,bx ; Offset to key
mov bl,offset tblpath
test flags,bysize
jz sort1
mov bl,offset tblsize ; Sort by size
sort1: test flags,bydate
jz sort2
mov bl,offset tbldate ; Sort by date/time
sort2: test flags,byext
jz sort3
mov bl,offset tblext

; Initialize sort parameters

sort3: mov cx,numdir ; Number of entries
mov numrec,cx
mov keyptr,bx

mov dx,64 ; Length of key
sub dx,bx
mov keylen,dx
mov es,segdir ; Seg addr of table
mov ax,es ; Save array addr
sub ax,4 ; adjust for indexing
mov base,ax

; Sort 64-byte entries

mov loc,cx ; Loc=NumRecs

check: cmp loc,1 ; IF Loc<=1 THEN
jg check1 ; GOTO SORTED
jmp sorted

check1: mov ax,loc
sar ax,1 ; Loc=2*(Loc/4)+1
or ax,1
mov loc,ax

mov ax,numrec ; Limit=NumRec-Loc
sub ax,loc
mov limit,ax

mov incr,0 ; Incr=0

again: inc incr ; Incr=Incr+1

mov ax,incr ; IF Incr>Limit THEN GOTO CHECK
cmp ax,limit
jg check

shl ax,1
shl ax,1
mov index1,ax ; Index1=Incr

mov index2,ax ; Index2=Index1+Loc
mov ax,loc
shl ax,1 ; times 2
shl ax,1 ; times 4
add index2,ax

comp: mov ax,index1 ; IF array(Index1)<=array(Index2)
add ax,base
mov es,ax
mov ptr1,ax
mov di,keyptr

mov ax,index2 ; THEN GOTO AGAIN
add ax,base
mov ptr2,ax
mov si,keyptr
mov cx,cs:keylen

push ds
mov ds,ax
repe cmpsb
pop ds
jae again

swap: mov bx,ptr1 ; ELSE
mov dx,ptr2 ; TEMP=array(Index1)

mov ax,cs
mov es,ax
mov di,offset temp
mov cx,tbl_len

mov ds,bx
sub si,si
rep movsb

mov es,bx ; array(Index1)=array(Index2)
mov ds,dx
sub di,di
sub si,si
mov cx,tbl_len
rep movsb

mov ax,cs ; array(Index2)=TEMP
mov ds,ax
mov si,offset temp
mov es,dx
sub di,di
mov cx,tbl_len
rep movsb

mov ax,index1 ; Index2=Index1
mov index2,ax

mov ax,loc ; Index1=Index1-Loc
shl ax,1
shl ax,1
sub index1,ax

jg comp ; IF Index1>0 then GOTO COMP
jmp again ; ELSE GOTO AGAIN

sorted: pop es ;Recover register
pop ds
sort endp


; Data structures and work areas

parmdr db ' :' ; Drive letter
parmdir equ $ ; for specific path

pline equ parmdir+64 ; Print line

dta equ pline+tbl_len ; Disk transfer areas

search equ dta + (depth+1)*dta_len ; Search arguments

local_stack equ search + (depth+1)*arg_len ; Local stack
local_stack_end equ local_stack+512

workend equ local_stack_end + 2 ; End of work areas

pgmsize equ (workend - cseg + 512) /16 ; Size of program

cseg ends
end ldir

  3 Responses to “Category : Assembly Language Source Code
Archive   : MISC_ASM.ZIP
Filename : LDIR.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: