home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
pcmag
/
asm4.arc
/
VTREE.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-02-05
|
9KB
|
294 lines
; VTREE -- A Visual Tree-structured subdirectory list
; =====
;
; (c) copyright Charles Petzold, 1985
;
; Assembler file: COM format
; Requirements: DOS 2.0 or higher
; Parameters: Optional Drive Specification
CSEG Segment
Assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
Org 005Ch
FCB Label Byte ; Will contain drive parameter
Org 0080h
DefaultDTA Label Byte ; Used for look-ahead searches
Org 0100h
Entry: Jmp Begin ; Program entry point
; Most Data
; ---------
SearchAsciiz db ?,":\*.*",0 ; ? gets drive spec
db '(C) Copyright Charles Petzold, 1985'
DriveError: db 'Invalid disk drive$' ; Error message
DosVersError db 'Requires DOS 2.0 +$' ; Another error message
FirstOrNext db 0 ; Flag for searches
LevelsIn dw 0 ; Directory level (0 = root)
SearchString db "\*.*",0 ; Asciiz for "all files"
SearchPointer dw 3 + Offset SearchAsciiz ; End of SearchAsciiz string
DtaPointer dw Offset EndProg ; Place for current DTA
DashCount dw ? ; For horizontal line count
; Check drive validity and DOS Version
; ------------------------------------
Begin: Cmp AL,0FFh ; Check for Valid Drive Specification
Jnz DriveSpecOK ; If OK, proceed
Lea DX,DriveError ; Otherwise print an error message!
ErrorExit: Mov AH,9 ; Print string
Int 21h ; by calling DOS
Int 20h ; And exit
DriveSpecOK: Mov AH,30h ; Use DOS to get the
Int 21h ; Version Number
Cmp AL,2 ; See if it's 2.0 or above
Jae DosVersOK ; If so, proceed
Lea DX,DosVersError ; Otherwise print an error message!
Jmp ErrorExit ; Print message & exit
; Get disk drive for tree
; -----------------------
DosVersOK: Mov AL,[FCB] ; Get drive parameter from FCB
Or AL,AL ; See if it's zero (default)
Jnz NotDefault ; If not, skip a few instructions
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
Cld ; All string directions forward
; 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 ; 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
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,Offset 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
Cmp Byte Ptr [DefaultDTA + 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
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: Int 20h ; Terminate program
; 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
; Other data areas here at end so COM file short as possible
; ----------------------------------------------------------
SubDirCounter Label Word ; Counts dir entries
EndProg equ 64 + Offset SubDirCounter ; DTAs go here
CSEG EndS
End Entry