home *** CD-ROM | disk | FTP | other *** search
- ; 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