code SEGMENT
ASSUME cs:code, ds:code
ORG 100h
start:
jmp begin
;----------------------------------------------------------------
DEFAULTDTA EQU 80h
DB 'Wm Cravener 520 Sharon Pa. 16146', 0
mainintro1 DB ' DirectoryTreeList by -Swift-Ware-', 13, 10, 0
mainintro2 DB '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~', 13, 10, 0
nomemory DB 'Not enough memory to run program.$'
pausenote DB 13, 10, ' - More - ', 0
linecount DW 0
pause_flag DB 0
searchasciiz DB ?, ":\*.*", 100 DUP (0)
searchstring DB "\*.*", 0
firstornext DB 0
levelsin DW 0
dashcount DW 0
searchpointer DW OFFSET searchasciiz + 3
dtapointer DW OFFSET endprog
;----------------------------------------------------------------
begin:
mov si, 81h ; wasn't first time-point to PSP.
back:
lodsb ; get a byte.
cmp al, ' ' ; throw away spaces.
je back
cmp al, '/' ; throw away backslash.
je back
and al, 5fh
cmp al, 'P' ; is it redirection?
jne wereready ; yes - must be something.
mov pause_flag, 0ffh
wereready:
mov ah, 4ah
mov bx, 1000h
int 21h
jnc looks_good
mov dx, OFFSET nomemory
mov ah, 9
int 21h
jmp terminate
looks_good:
cld ; All string directions forward
call clear
mov ah, 2
mov bh, 0
mov dx, 0000h
int 10h
mov si, OFFSET mainintro1
call writestring
mov ah, 2
mov bh, 0
mov dx, 0100h
int 10h
mov si, OFFSET mainintro2
call writestring
mov ah, 2
mov bh, 0
mov dx, 0200h
int 10h
mov ah, 19h ; Get default drive
int 21h ; by calling DOS
inc al ; Turns drive A: = 0 to drive A: = 1
notdefault:
mov dl, al ; Set DL to drive number (A: = 1)
add al, '@' ; Convert to character "A", etc
mov searchasciiz, al ; Put it in our search string
call printchar
mov al, ':'
call printchar
mov al, '\'
call printchar
mov al, 0dh
call printchar
mov al, 0ah
call printchar
; Do *.* search for sub-directories
; ---------------------------------
mainloop:
mov dx, dtapointer ; Get current DTA address
mov ah, 1ah ; Set the DTA
int 21h ; by calling DOS
mov bx, levelsin ; BX represents level
add bx, bx ; Double it for addressing
cmp firstornext, 0 ; See if this is first search
jnz findnextfile ; If not, skip some code
mov WORD PTR [subdircounter + bx], 0 ; Count starts at 0
mov dx, OFFSET searchasciiz ; Directory to search for
mov cx, 10h ; Directory attribute search
mov ah, 4eh ; Find first file
int 21h ; by calling DOS
jmp SHORT testmatch ; See if we've got match
findnextfile:
mov ah, 4fh ; Otherwise find next file
int 21h ; by calling DOS
testmatch:
jnc testattr ; If CY flag not set, continue
jmp nomorefiles ; Otherwise, no more files
testattr:
mov si, dtapointer ; SI now points to DTA
cmp BYTE PTR [si + 21], 10h ; Test if a directory
jnz findnextfile ; If not, loop up for next
founddirentry:
add si, 30 ; SI points to directory name
cmp BYTE PTR [si], '.' ; See if it's . or .. entry
jz findnextfile ; If so, loop up for next
; Have found a valid directory entry
; ----------------------------------
inc WORD PTR [subdircounter + bx] ; Got another one
mov cx, levelsin ; Number of levels deep
jcxz lookaheadsearch ; If root, skip indentation
cmp WORD PTR [subdircounter + bx], 1 ; See if first found
jz nospacein ; If so, no indentations
sub bx, bx ; Start index at zero
indentloop:
mov al, 179 ; Vertical line character
test WORD PTR [subdircounter + bx], 8000h
jz gotcontinuechar ; Use if still more dirs left
mov al, ' ' ; Otherwise use a blank
gotcontinuechar:
call printchar ; And print it
push cx ; Save the levels count
mov cx, 16-4 ; Need 16 blanks indentation
blankloop:
mov al, ' ' ; This is the blank
call printchar ; We print it
loop blankloop ; And loop for the next
pop cx ; Retrieve the levels count
inc bx ; Kick up the levels index
inc bx ; Twice because word access
loop indentloop ; Loop for all the levels
nospacein:
cmp WORD PTR [subdircounter + bx], 1 ; See if first one
jnz lookaheadsearch ; If not skip a little
mov cx, dashcount ; Number of lines to print
sub cx, 4
dashprint:
mov al, 196 ; Horizontal line character
call printchar ; Print them
loop dashprint ; And loop for whole count
; Check for more directories to determine proper line characters
; --------------------------------------------------------------
lookaheadsearch:
push si ; Save ptr to directory name
mov si, dtapointer ; Set source to DTA
mov di, DEFAULTDTA ; Set destination to 80h
mov dx, di ; Also DX (used later)
mov cx, 43 ; 43 characters to transfer
rep movsb ; Move them in
pop si ; Get back directory name ptr
mov ah, 1ah ; Set a new DTA
int 21h ; by calling DOS
checkifanymore:
mov ah, 4fh ; Find the next file
int 21h ; by calling DOS
jc cantfindanother ; CY set if can't find one
mov di, defaultdta ; need default DTA
cmp BYTE PTR [di + 21], 10h ; Test if a directory
jnz checkifanymore ; If not, gotta try again
mov al, 194 ; Horizontal w/ vertical below
cmp WORD PTR [subdircounter + bx], 1
jz gotgoodchar ; This is good if it's first
mov al, 195 ; Vertical w/ horizontal right
jmp SHORT gotgoodchar ; Other than first found
cantfindanother:
mov al, 196 ; Horizontal line character
cmp WORD PTR [subdircounter + bx], 1
jz gotgoodchar ; This is good if first one
mov al, 192 ; Lower left corner
or WORD PTR [subdircounter + bx], 8000h ; Flag no more
gotgoodchar:
call printchar ; Print that character also
mov al, 196 ; Horizontal line character
call printchar ; Another print
mov al, ' ' ; Space before file name
call printchar ; Print the space
; Now print name of directory and append to SearchPointer string
; --------------------------------------------------------------
mov cx, 13 ; Number of characters in name
mov di, searchpointer ; End of current search asciiz
printnameloop:
lodsb ; Get the directory name character
or al, al ; Check if it's zero terminator
jz endofname ; If so, we're at the end
stosb ; Save on end of search asciiz
call printchar ; And print it also
loop printnameloop ; Loop for maximum number of chars
endofname:
mov al, ' ' ; Stick a blank at the end
call printchar ; Print the blank
mov dashcount, cx ; Save for later dashes at end
fixupsearch:
mov searchpointer, di ; New end of asciiz string
inc searchpointer ; Point to next character
mov si, OFFSET searchstring ; Will move in \*.*, 0 string
mov cx, 5 ; It's only five characters
rep movsb ; Move it ine
inc levelsin ; We're one level deeper now
mov firstornext, 0 ; Prepare for search first
add dtapointer, 43 ; New DTA will be needed
jmp mainloop ; Back up to beginning
; When no more files are found, time to back up to previous subdirectory
; ----------------------------------------------------------------------
nomorefiles:
cmp levelsin, 0 ; See if we're back in root
jz terminate ; If so, we're all done!
test WORD PTR [subdircounter + bx], 7fffh
jnz backuponedir ; If at least one file found
cmp pause_flag, 0
je skippause
call max_24_lines
skippause:
mov al, 13 ; A carriage return
call printchar ; is printed
mov al, 10 ; A line feed
call printchar ; makes a new line
backuponedir:
mov di, OFFSET searchasciiz ; Let's look at search string
mov cx, 70 ; It could have 70 characters
mov al, 0 ; We'll search for a zero
repnz scasb ; Let's do it
dec di ; So points to zero
mov cx, 64 ; Now we'll search backwards
mov al, '\' ; For last slash
std ; Backwards search
repnz scasb ; Do it once
repnz scasb ; Again for dir we're leaving
inc di ; So points to slash
mov searchpointer, di ; New end of asciiz string
inc searchpointer ; Actually one character more
mov si, OFFSET searchstring ; Now append \*.*, 0 to it
mov cx, 5 ; Five characters
cld ; In forward direction
rep movsb ; Move them int
dec levelsin ; We go back one level
mov firstornext, 1 ; Have to search next, not 1st
sub dtapointer, 43 ; Previous DTA will be used
jmp mainloop ; Back up to beginning
terminate:
mov al, 0dh
call printchar
mov al, 0ah
call printchar
mov ax, 4c00h ; Terminate program
int 21h
; Writestring subroutine -- prints a string of characters
; --------------------------------------------------------
writestring:
push si
next:
lodsb
cmp al, 0
je done
call printchar
jmp SHORT next
done:
pop si
ret
; PrintChar subroutine -- prints a character on the screen
; --------------------------------------------------------
printchar:
push dx
mov dl, al ; DL gets the character
mov ah, 2 ; Print character on display
int 21h ; by calling DOS
pop dx
ret
; Clear screen subroutine -- clears video screen
; ----------------------------------------------------------
clear:
mov ah, 8 ; Get current screen
mov bh, 0 ; color for clearing
int 10h
mov bh, ah ; the current color
mov ah, 6
mov al, 0 ; Scroll whole screen
mov cx, 0
mov dx, 184fh
int 10h
ret
;-----------------------------------------------;
; This subroutine displays 24 lines then pause. ;
;-----------------------------------------------;
max_24_lines:
push ds
push cs
pop ds
inc WORD PTR [linecount]
cmp WORD PTR [linecount], 21
jl no_pause
mov si, OFFSET pausenote
call writestring
mov ah, 0
int 16h
call scroller
mov WORD PTR [linecount], 0
no_pause:
pop ds
ret
scroller:
mov ah, 8
mov bh, 0
int 10h
mov bh, ah
mov ah, 6
mov al, 0
mov cx, 0300h
mov dx, 184fh
int 10h
mov ah, 2
mov bh, 0
mov dx, 0200h
int 10h
ret
;------------------------
; Other data areas here at end so COM file short as possible
;-----------------------------------------------------------------
SUBDIRCOUNTER EQU $
ENDPROG EQU 64 + OFFSET SUBDIRCOUNTER ; DTAs go here
;-----------------------------------------------------------------
code ENDS
END start