home *** CD-ROM | disk | FTP | other *** search
- ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- ;
- ; Name : GETDIRS.ASM
- ;
- ; Revised : 08-Apr-1990
- ;
- ; Overview : This is a HIGHLY specialized function which reads the ENTIRE
- ; DIRECTORY of a given disk(ette).
- ; It finds ALL sub-directories on the drive, and places their
- ; names in the passed array.
- ; An INTEGER value is RETURNed, which is the number of
- ; directories found.
- ;
- ; Notes : - Due to the structure of the program, successful assembly
- ; requires the Microsoft MACRO ASSEMBLER, V 5.1 +.
- ; - This routine has an INTERNAL limit on the maximum number of
- ; sub-directories it will find, controlled by "MaxDirs"
- ; - This routine would be declared in your source program as
- ; an external FUNCTION routine, via the statement -
- ;
- ; DECLARE FUNCTION GetDirs% (Drv%, SSeg%, SOff%)
- ;
- ; Parameters : The parameters to the above CALL are defined as follows:
- ;
- ; Drv = Represents the drive in which the disk(ette) to be
- ; read is located; for example Drive = 1 = use
- ; drive A:, Drive = 2 = use drive B:, etc.
- ; NOTE : The calling program MUST insure that the Drive parm
- ; is acceptable - this program will not check.
- ;
- ; SSeg = The SEGMENT address of a DYNAMIC ARRAY which has been
- ; DIMmed to hold the names of all the SubDirs found by
- ; this routine. This array is defined as -
- ; {arrayname} (1 to MaxDirs) AS STRING * 66
- ;
- ; SOff = The OFFSET address of the above array.
- ;
- ; The easiest way to CALL this FUNCTION is as follows -
- ;
- ; NmbrOfSubDirs% = GetDirs% (1, VARSEG(SDarray(2)),VARPTR(SDArray(2)))
- ;
- ; - Note that SDarray starts at element 2. This is so that,
- ; on return, SDarray(1) may be filled in with the some string
- ; identifying it as the ROOT directory (this routine ignores
- ; SDarray(1)).
- ; - Note, too, that the integer returned by this routine will be
- ; adjusted to INCLUDE the root directory even though this routine
- ; does NOT place the root directory path into SDarray(1).
- ; (This helps you when you do a FOR...NEXT loop, since the
- ; numeric return of this program can be used directly to print
- ; the SDarray() contents)
- ;
- ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
- .MODEL MEDIUM,BASIC
- .DATA
-
- MaxDirs EQU 100 ; INTERNAL LIMIT ON NUMBER OF SUB-DIRS
-
- DirRoot DB 'A:*.*',0 ; Used to search for VOLUME LABEL
- Path DB 'A:\',0,0,0,0
- Subs DB MaxDirs dup(66 dup(0)) ; Stores sub-Directories
- DirBlank DB 'A:\',63 dup(0)
-
- Return_To DB 'A:\',64 dup(0) ; Returns here when done
-
- _NewDTABuffer DB 128 dup(0)
- _DTABuff EQU OFFSET _NewDTABuffer
- _DTAFileAttr EQU _DTABuff + 21
- _DTAFileName EQU _DTABuff + 30
-
- START_SUBS EQU OFFSET Subs
- PATH_ROOT EQU OFFSET Path
- START_DIRBLANK EQU OFFSET DirBlank
- PATH_RETURN EQU OFFSET Return_To
-
- EVEN
-
- CtrSubDir DW ? ; Counter for # sub directories found
- PtrSubDir DW ? ; Keeps track of pointer to SDarray()
- CtrSubLoop DW ?
- SegSubDir DW ? ; SEGMENT address of passed SDarray()
- OffSubDir DW ? ; OFFSET address of passed SDarray()
- ;==============================================================================
- .CODE
-
- GetDirs PROC USES DS ES SI DI, DRIVE:word, SDSEG:word, SDOFF:word
- LOCAL OldDTASeg:word, OldDTAOff:word, CurrDrive:word
-
- ;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
- SubEND MACRO
- mov byte ptr[DI],'\' ; This will allow this entry in SubDirs
- mov byte ptr[DI+1],'*' ; to be used as a new
- mov byte ptr[DI+2],'.' ; search criteria
- mov byte ptr[DI+3],'*'
- mov byte ptr[DI+4],0 ; Makes it an ASCIIZ string
- ENDM
- ;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
- DTAClr MACRO
- LOCAL CD_Loop
- mov DI,_DTAFileName ; ES:DI = start of FileName
- ; in New_DTABuff
- mov CX,49 ; We will MOVe 49 words here (98 bytes)
- xor AX,AX ; (i.e., 98 bytes of 0)
- CD_Loop:
- stosw
- loop CD_Loop
- ENDM
- ;******************************************************************************
- ; Start Of Main Program Code
- ;******************************************************************************
- xor AX,AX ; Clear to 0 to for the next 4 lines
- mov CtrSubDir,AX
- mov PtrSubDir,AX
- mov CtrSubLoop,AX
- ;------------------------------------------------------------------------------
- ; Below, we will obtain the drive ID of the current default drive and
- ; path and store them so that we can return to the starting drive and
- ; path upon exit from this routine.
- ;------------------------------------------------------------------------------
- mov AH,19h ; Get and store the Current DRIVE ID
- int 21h
- xor AH,AH ; Clear out AH
- mov CurrDrive,AX ; CurrDrive of 0 = A, of 1 = B, etc
-
- add AL,65 ; Make AL = letter equivalent of drive
- mov SI,PATH_RETURN
- mov [SI],AL
- add SI,3 ; DS:SI = buffer for next int 21h call
-
- sub AL,64 ; Adjust AL from letter to drive value
- mov DL,AL ; DL = Current default drive
- mov AH,47h ; "GET CURRENT DIRECTORY" request
- int 21h
- ;------------------------------------------------------------------------------
- ; Since this routine makes extensive use of the DTA, we will protect the
- ; DTA which the CALLing program uses by setting up a new DTA,
- ; temporarily, for this routine to use. Therefore, we must store the
- ; SEGMENT:OFFSET address of the current DTA so that we can restore it on
- ; exit from this routine
- ;------------------------------------------------------------------------------
- mov AH,02Fh ; "GET DTA ADDR" Service of int 21h
- int 21h
- mov OldDTASeg,ES ; Save the entry value for the DTA
- mov OldDTAOff,BX
- ;------------------------------------------------------------------------------
- ; Now we can get the passed parameters for the SEGMENT and OFFSET of the
- ; DYNAMIC array which will hold the file names.
- ; Then we can the passed DRIVE parameter and change the current default
- ; drive / path to ROOT of the passed DRIVE.
- ;------------------------------------------------------------------------------
- mov BX,SDSEG ; Save the SEGMENT address of SDarray
- mov AX,[BX]
- mov SegSubDir,AX ; Place it into SegSubDir
- mov BX,SDOFF ; Save the OFFSET address of SDarray
- mov AX,[BX]
- mov OffSubDir,AX ; Place it into OffSubDir
-
- mov BX,DRIVE ; BX = the address of the passed parm,
- ; DRIVE (1 = A; 2 = B;, etc)
- mov AX,[BX] ; AX = the value of the DRIVE parm
-
- dec AL ; Note the disparity here!
- mov DL,AL ; Put PASSED DRIVE SPEC into DL
- mov AH,0Eh ; "SELECT DISK" request of int 21h
- int 21h
- ;------------------------------------------------------------------------------
- ; Now we will use the passed DRIVE parm to fill in our search strings
- ;------------------------------------------------------------------------------
- mov BX,DRIVE
- mov AX,[BX]
- add AL,64 ; Convert passed DRIVE number to letter value
- mov SI,OFFSET DirRoot
- mov [SI],AL
- mov SI,START_DIRBLANK
- mov [SI],AL
- mov SI,PATH_ROOT
- mov [SI],AL
-
- mov DX,START_DIRBLANK ; DX = ROOT of passed Drive Spec
- mov AH,03Bh ; "SET DIRECTORY" to ROOT of passed Spec
- int 21h
-
- mov AX,DS
- mov ES,AX ; Be Sure ES = DS for now
- ;------------------------------------------------------------------------------
- ; Below, we will be sure that the SubDirs area is blank before we start,
- ; and that each row starts with the passed DRIVE parameter, followed by
- ; ":\" - this will allow us to later use these subdir names as full path
- ; specs when searching for other subdirectories.
- ;------------------------------------------------------------------------------
- mov SI,START_DIRBLANK
- mov DI,START_SUBS
- xor BX,BX
- ReplaceDriveSpec:
- mov CX,66 ; This loop transfers the drive spec
- rep movsb ; and the trailing 63 "0"'s
- ; into each of the SubDirs
- mov SI,START_DIRBLANK ; Point DS:SI at start of Blank format
- inc BX ; Keep count of how many SubDirs
- ; have been filled
- cmp BX,MaxDirs ; Have we hit the INTERNAL limit?
- jb ReplaceDriveSpec
- ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
- Start_Of_Program:
- mov DX,_DTABuff ; Prepare to set NEW DTA temporarily
- mov AH,01Ah ; "SET DTA ADDR" Service of int 21h
- int 21h
- clc ; Clear Carry Flag to start
-
- mov AX,DS
- mov ES,AX ; Make ES = DS
- mov DI,PATH_ROOT ; The "Path" variable now points to
- inc DI ; an ASCIIZ string which can be
- inc DI ; used to find all files in ROOT
- SubEND
- ;------------------------------------------------------------------------------
- ; The process below starts in the ROOT directory and is designed to find
- ; all files EXCEPT the volume label, including ALL sub-directory entries.
- ;------------------------------------------------------------------------------
- mov SI,_DTABuff ; Point SI at start of _NewDTABuffer
- mov DX,PATH_ROOT ; "Path" is the ROOT Dir entry
- mov CX,16h ; Find ANY ATTRIBUTE file
- mov AH,04Eh ; "FIND FIRST MATCH" Service of int 21h
- int 21h
-
- jnc DiskNotEmpty ; If CARRY, disk is 100% EMPTY
- jmp RetToCaller
- ;------------------------------------------------------------------------------
- ; We have determined that the disk(ette) is NOT empty, since some sort of
- ; directory entry has been found.
- ; Note that this entry CANNOT be either a "." or ".." type file, since we
- ; are in the ROOT directory at this point.
- ; Let us first see if we have hit a sub-directory, or a "real" file -
- ; note at this point, DS:SI points at start of _NewDTABuffer.
- ;------------------------------------------------------------------------------
- DiskNotEmpty:
- mov SI,_DTAFileAttr ; DS:SI now = attribute of found file
- cmp byte ptr[SI],10h ; Is this a sub-Directory?
- jne GetNextMatch ; - No - just try again
-
- mov DI,START_SUBS ; Point DI at start of SubDirs - past
- add DI,3 ; the "A:\" portion
- mov CX,CtrSubDir
- inc CtrSubDir ; Keep count of SubDirs, too
- mov AX,66 ; Save new starting point in SubDirs
- mul CL
- add DI,AX
- mov PtrSubDir,DI
- mov SI,_DTAFileName ; DS:SI = name in _NewDTABuffer area
- RecordFirstLevelSubDir:
- lodsb
- cmp AL,0 ; Note 0 = terminator of sub-Dir name
- je EndSubDirName
- stosb
- jmp short RecordFirstLevelSubDir
- EndSubDirName:
- SubEND ; Finish sub-Dir name with search criteria
- ;------------------------------------------------------------------------------
- ; At this point, we are still in the ROOT, and must now look for another
- ; matching subdir (if any exist).
- ;------------------------------------------------------------------------------
- GetNextMatch:
- DTAClr ; Point DI at start of _NewDTABuffer
- mov SI,_DTABuff
- mov DX,PATH_ROOT ; Because we are still in the ROOT...
- mov CX,16h
- mov AH,04Fh ; "FIND NEXT MATCH" Service of int 21h
- int 21h
- jnc DiskNotEmpty
- ;------------------------------------------------------------------------------
- ; At this point, we have finished the ROOT directory and recorded all
- ; the sub-directories into the SDarray.
- ; Note that number of sub-directories is in the variable,
- ; CtrSubDir, while the offset into the SDarray is in PtrSubDir.
- ;------------------------------------------------------------------------------
- mov CX,CtrSubDir
- cmp CX,0
- jne SubDirStepTwo ; Exit here if NO sub-directories
- jmp RetToCaller
- SubDirStepTwo:
- mov SI,START_SUBS
- mov AX,66
- mov CX,CtrSubLoop ; This will keep place as we step thru
- inc CtrSubLoop
- cmp CX,CtrSubDir
- jb SubDirStepThree
- jmp short RetToCaller ; This is the END OF THE SHOW
- SubDirStepThree:
- mul CL
- add SI,AX ; Now DS:SI points at right offset
- ; into SDarray()
- mov DX,SI ; For use a few steps from now
-
- mov SI,_DTABuff
- mov CX,16h
- mov AH,04Eh ; "FIND FIRST" in this SubDir
- int 21h
-
- jc SubDirStepTwo ; Try the NEXT sub-Directory
- FoundSubDirFile:
- mov SI,_DTAFileAttr
- mov AL,[SI]
- cmp AL,10h ; Is this a sub-sub...?
- jne MoreFilesInSubDir ; - No
- add SI,09 ; - Maybe... but
- cmp byte ptr[SI],'.' ; ignore all "." and ".."
- je MoreFilesInSubDir
-
- mov AX,PtrSubDir
- add AX,66
- mov DI,AX
- mov PtrSubDir,AX ; PtrSubDir = next open row SDarray
- inc CtrSubDir ; Keep the count straight
- mov SI,DX
- add SI,3
- MoveSubSubName:
- lodsb
- cmp AL,'*'
- je MakeNewPath
- stosb
- jmp short MoveSubSubName
- MakeNewPath:
- mov SI,_DTAFileName ; Again points at _NewDTABuffer FileName
- MNPAA:
- lodsb
- cmp AL,0
- je EndNewPath
- stosb
- jmp short MNPAA
- EndNewPath:
- SubEND
- MoreFilesInSubDir:
- DTAClr
- mov CX,16h
- mov SI,_DTABuff ; DS:DX still points at correct SubDirs
- mov AH,04Fh
- int 21h
-
- jnc FoundSubDirFile
- jmp SubDirStepTwo
- ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
- RetToCaller:
- mov BX,DS ; Save DS temporarily
- mov AX,OldDTASeg ; Here we restore the entry DTA address
- mov DS,AX
- ASSUME DS:NOTHING
-
- mov DX,OldDTAOff
- mov AH,01Ah ; "SET DTA ADDR" Service of int 21h
- int 21h
-
- mov DS,BX ; Now restore DS from BX
- ASSUME DS:DGROUP
-
- mov DX,CurrDrive
- mov AH,0Eh
- int 21h ; Restore Entry Default Drive
-
- mov DX,PATH_RETURN ; Restore Entry Default Directory
- mov AH,03Bh
- int 21h
-
- mov AX,CtrSubDir
- mov CL,66 ; CL = max length of a SubDirName
- mul CL ; Multiply by the number of found
- ; SubDirs to get total # bytes
- ; to move.
- mov CX,AX ; CX will control the loop
- jcxz FastExitGetDirs ; If CX = 0 then NO subdirs were found
-
- mov SI,START_SUBS ; Point DS:SI at start of SubDir Names
- mov AX,SegSubDir
- mov ES,AX
- mov DI,OffSubDir ; Point ES:DI at start of SDarray
- TransSDChar:
- lodsb ; Move all the characters,
- ; except for trailing "*.*"
- cmp AL,'*'
- je Lose_This_Char
- cmp AL,'.'
- je Lose_This_Char
- cmp AL,32 ; If the AL value < 32, substitute
- ; blank spaces, since you may
- ; need / want to use the QB
- jae Keep_Sub_Dir_Char ; function, "RTRIM$" (eliminate
- ; the trailing CHR$(0)'s)
- Lose_This_Char:
- mov AL,32 ; Replace offending char with blank
- Keep_Sub_Dir_Char:
- stosb
- loop TransSDChar
-
- mov AX,CtrSubDir ; Return number of subdirectories
- inc AX ; Correct the count for root dir
- FastExitGetDirs:
- ret ; PROGRAM TERMINATION
-
- GetDirs ENDP
- END
-
- ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-