Author |
Topic: lbbTree - a replacement for MSWin TREE.EXE (Read 228 times) |
|
CirothUngol
New Member
member is offline
Odie, Odie, cha cha cha.
Gender:
Posts: 44
|
|
lbbTree - a replacement for MSWin TREE.EXE
« Thread started on: Jul 17th, 2017, 10:56pm » |
|
I've written a recursive file search routine based around LB Booster's new FILES function. To test and showcase it, I decided to write a replacement for TREE.EXE, the MS Windows console program that graphically displays an entire folder tree. I've closely emulated the operation, function, and appearance of the original, but have also added several new options. Useful functions included are:
* cmdln(cl$,mode) Breaks CommandLine$ into parameters, stores them in cmdln$(), and returns count. mode 0=keep quotes, 1=omit quotes. * dirExists(BYREF path$) Resolves path relativity, fixes capitalization, and returns 1 if path exists. * fileCount(path$,filter$,mode) Recursive count of path$\filter$. Returns number of occurances. mode 0=files, 1=files+folders. * rFiles(path$,filter$,BYREF a$()) Recursive search for path$\filter$. Loads a$() with file/folder info. Returns number of files found.
Be sure to compile as a console program, otherwise all text is dumped to MAINWIN. Copy and paste the following Code:' lbbTree v1.0 on 2017-07-17 by CirothUngol using LB Booster v3.08
' Compile as a console app, otherwise output is sent to MainWin.
' Intended as an improved replacement for Windows' TREE.EXE.
'
' lbbTree [drive:][path] [/A] [/C] [/F] [/M] [/O] [/S filter] [/T] [/?]
'
' /A Use ASCII instead of extended characters.
' /C Use alternative character set.
' /F Display the names of the files in each folder.
' /L Use less spacing for the margins.
' /M Display more folder/file information.
' /O Display only folders that contain files.
' /S Search for file names matching filter. */? are allowed.
' /T Truncate display to 79 characters per line.
' /? Display this help screen.
'
' Other differences:
' Always displays the PATH (TREE displays 'drive:.' if no path provided)
' Displays PATH as found on disk (TREE displays all uppercase)
' Displays search filter if provided (TREE doesn't filter file names)
' Displays version number on help screen (TREE doesn't provide it)
' Accepts input path with a trailing backslash (TREE rejects as invalid)
' Accepts switches enclosed in double-quotes (TREE assumes a PATH)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ver$ = "1.0"
cr$ = CHR$(13)
'''''''''''''''''''''''
' parse the commandline
x = cmdln(CommandLine$,1)
WHILE x > y
y += 1
SELECT CASE LOWER$(cmdln$(y))
CASE "/a" ' use Ascii text
IF mode AND 1 THEN CALL errOut "Parameter format not correct - "; cmdln$(y)
mode += 1
CASE "/c" ' use alternate Characters
IF mode AND 2 THEN CALL errOut "Parameter format not correct - "; cmdln$(y)
mode += 2
CASE "/o" ' Only folders containing files
IF mode AND 4 THEN CALL errOut "Parameter format not correct - "; cmdln$(y)
mode += 4
CASE "/f" ' display File names
IF mode AND 8 THEN CALL errOut "Parameter format not correct - "; cmdln$(y)
mode += 8
CASE "/m" ' display More info
IF mode AND 16 THEN CALL errOut "Parameter format not correct - "; cmdln$(y)
mode += 16
CASE "/t" ' truncate display to 79 characters
IF mode AND 32 THEN CALL errOut "Parameter format not correct - "; cmdln$(y)
mode += 32
CASE "/l" ' use less spacing in margins
IF mode AND 64 THEN CALL errOut "Parameter format not correct - "; cmdln$(y)
mode += 64
CASE "/s" ' Search for file names
IF mode AND 128 THEN CALL errOut "Parameter format not correct - "; cmdln$(y); " "; cmdln$(y+1)
mode += 128
y += 1
IF x >= y THEN filter$ = cmdln$(y)
CASE "/?" ' display help screen
CALL lbbTreeHelp ver$
CASE ELSE ' drive:\path
IF LEFT$(cmdln$(y),1) = "/" THEN CALL errOut "Invalid switch - "; cmdln$(y)
IF path$ <> "" THEN
x = cmdln(CommandLine$,0)
CALL errOut "Too many parameters - "; cmdln$(y)
END IF
path$ = cmdln$(y)
END SELECT
WEND
X = dirExists(path$)
IF X = -1 THEN CALL errOut "Invalid drive specification"
'''''''''''''''''''''''''''''''''''
' get volume name and serial number
p$ = LEFT$(path$,2); "\"
vName$ = SPACE$(_MAX_PATH); CHR$(0)
vNameSize = _MAX_PATH+1
STRUCT vSerial, sn as ulong
CALLDLL #kernel32, "GetVolumeInformationA",_
p$ as ptr,_
vName$ as ptr,_
vNameSize as ulong,_
vSerial as struct,_
0 as long, 0 as long, 0 as long, 0 as long,_
result as boolean
IF result = 0 THEN CALL errOut "Invalid volume specification"
vSerial$ = RIGHT$("0000000"; dechex$(vSerial.sn.struct),8)
PRINT "Folder PATH listing for volume "; LEFT$(vName$,INSTR(vName$,CHR$(0))-1)
PRINT "Volume serial number is "; LEFT$(vSerial$,4); "-"; RIGHT$(vSerial$,4)
IF X = 0 THEN CALL errOut path$;cr$;"Invalid path - ";MID$(path$,3);cr$;"No subfolders exist"
CALL lbbTree path$, filter$, lbbTree$(), mode
END
''''''''''''''''''''''''''''''''
' display error message and exit
SUB errOut display$
PRINT display$
END
END SUB
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'NAME=cmdln
'AUTHOR=CirothUngol
'ITEM=FUNCTION cmdln(cl$, mode)
'DESCRIPTION=Breaks cl$ into parameters, stores them in cmdln$(), and returns # of parameters.
FUNCTION cmdln(cl$, mode)
' cmdln$(0) = # of items in array.
' mode +0 - Retain double-quotes on parameters
' mode +1 - Remove double-quotes from parameters
d$ = CHR$(0)
q$ = CHR$(34)
cl$ = TRIM$(cl$)
mode = mode AND 1
WHILE cl$ <> ""
IF LEFT$(cl$,1) = q$ THEN
p = INSTR(cl$,q$,2)
IF p = 0 THEN p$ = MID$(cl$,1+mode)
IF p > 0 THEN p$ = MID$(cl$,1+mode,p-mode*2)
cl$ = MID$(cl$,LEN(p$)+mode*2+1)
ELSE
p$ = WORD$(cl$,1)
cl$ = MID$(cl$,LEN(p$)+1)
END IF
param$ = param$; p$; d$
cmdln += 1
cl$ = TRIM$(cl$)
WEND
REDIM cmdln$(cmdln)
cmdln$(0) = STR$(cmdln)
FOR p = 1 TO cmdln
cmdln$(p) = WORD$(param$,p,d$)
NEXT p
END FUNCTION
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'NAME=dirExists
'AUTHOR=CirothUngol
'ITEM=FUNCTION dirExists(BYREF path$)
'DESCRIPTION=Resolves and saves path$. Return 1=path exists, -1=invalid drive, 0=invalid folder.
FUNCTION dirExists(BYREF path$)
'Arguments:
'path$ - Name of FolderPath to check for existence. If Full Path
' is not provided, then StartupDir$ is used.
IF path$ = "" THEN
path$ = StartupDir$
dirExists = 1
EXIT FUNCTION
END IF
' resolve relative paths and save to path$
IF INSTR(path$,"\") = 1 THEN path$ = LEFT$(StartupDir$,2); path$
IF INSTR(path$,":") <> 2 THEN path$ = StartupDir$; "\"; path$
FILES path$, "\", x$()
path$ = x$(0,2); x$(0,3)
path$ = LEFT$(path$,LEN(path$)-1)
' check for invalid drive
d$ = LOWER$(LEFT$(path$,2))
DO
X += 1
t$ = WORD$(Drives$,X)
LOOP UNTIL (t$ = "") OR (t$ = d$)
IF t$ = "" THEN
dirExists = -1
EXIT FUNCTION
END IF
' check for invalid folder & correct path capitalization
d$ = UPPER$(LEFT$(path$,2))
p$ = LOWER$(path$)
t$ = WORD$(p$,2,"\")
X = 2
WHILE t$ <> ""
FILES d$, "\", x$()
FOR i = 1 TO VAL(x$(0,1))
IF LOWER$(x$(i,1)) = t$ THEN d$ = d$; "\"; x$(i,1)
NEXT i
X += 1
t$ = WORD$(p$,X,"\")
WEND
IF LOWER$(d$) <> p$ THEN EXIT FUNCTION
' drive:\dir exists, save path and exit
dirExists = 1
path$ = d$
END FUNCTION
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'NAME=fileCount
'AUTHOR=CirothUngol
'ITEM=FUNCTION fileCount(path$, filter$, mode)
'DESCRIPTION=Recursive count of path$\filter$. Returns number of occurances.
FUNCTION fileCount(path$, filter$, mode)
' If path$ is empty, StartupDir$ is assumed. If filter$ is empty, "*" is assumed.
' Return mode 0=num of files, 1=files + folders. Set filter$="\" for folders only.
IF path$ = "" THEN path$ = StartupDir$
IF filter$ = "" THEN filter$ = "*"
FILES path$, filter$, x$()
numFiles = VAL(x$(0,0))
numFolders = VAL(x$(0,1))
fileCount = numFiles
IF mode AND 1 THEN fileCount += numFolders
' recurse through all found folders
FOR count = 1 TO numFolders
subPath$ = subPath$; x$(0,2); x$(0,3); x$(numFiles+count,1); ">"
NEXT count
FOR count = 1 TO numFolders
fileCount += fileCount(WORD$(subPath$,count,">"), filter$, mode)
NEXT count
END FUNCTION
...then see the next post for the final two functions.
|
|
Logged
|
LB Booster + LB Workshop + LB Builder = My Programs on Google Drive
|
|
|
CirothUngol
New Member
member is offline
Odie, Odie, cha cha cha.
Gender:
Posts: 44
|
|
Re: lbbTree - a replacement for MSWin TREE.EXE
« Reply #1 on: Jul 17th, 2017, 11:03pm » |
|
Copy the previous post and tack on the following Code:''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'NAME=rFiles
'AUTHOR=CirothUngol
'ITEM=FUNCTION rFiles(path$, filter$, BYREF a$())
'DESCRIPTION=Recursive search for path$\filter$. Loads a$() with file/folder info. Returns number of files found.
FUNCTION rFiles(path$, filter$, BYREF a$())
' This function is modeled directly on the LB Booster FILES function, and the array a$() that
' it builds is intended to closely mirror that which is created by FILES. The arguments are:
' path$ - The root folder to recursively search for files. If empty, StartupDir$ is assumed.
' filter$ - The file name to search for. Wildcards are allowed. If empty, "*" is assumed.
' a$() - 2D array passed BYREF is REDIMed and loaded with file/folder info.
'
' Much like the FILES statement, rFiles() will fill the array a$() in this fashion:
' a$(0, 0) - The number of files found
' a$(0, 1) - The number of folders found, including root folder
' a$(0, 2) - The root drive spec
' a$(0, 3) - The root directory path
' a$(0, 4) - Total size of all files found
' a$(0, 5) - Full root directory path
'
' Then starting at a$(1, y), you will have the following file information:
' a$(x, 0) - The file name
' a$(x, 1) - The file size
' a$(X, 2) - The file date/time "MM/DD/YY 12:mm:ss AM|PM" (local time)
' a$(X, 3) - The file attributes
' a$(X, 4) - The file date/time "YYYY-MM-DD 24:mm:ss" (GMT)
' a$(x, 5) - Additional Path\To\
'
' totalFiles = VAL(a$(0, 0))
' folder information starts with the root folder at a$(totalFiles + 1, y):
' a$(totalFiles + x, 0) - The folder name
' a$(totalFiles + x, 1) - Total size of files found in folder
' a$(totalFiles + x, 2) - Index to 1st file in folder, or blank if none
' a$(totalFiles + x, 3) - Number of files found in folder
' a$(totalFiles + x, 4) - Number of subfolders found in folder
' a$(totalFiles + x, 5) - Additional Path\To\
'
' Using this info, you can reconstruct the full path to file/folder X thusly:
' fullPath$ = a$(0, 5); a$(X, 5); a$(X, 0)
''''''''''''''''''''''''''''''''''''''''''
IF path$ = "" THEN path$ = StartupDir$
IF filter$ = "" THEN filter$ = "*"
rFiles = fileCount(path$,filter$,0)
totFolders = fileCount(path$,"\",1) + 1 ' +1 for the root folder
fi = 0 ' file index
di = rFiles ' folder index
REDIM a$(rFiles + totFolders,5)
FILES path$, "\", x$()
a$(0,0) = STR$(rFiles)
a$(0,1) = STR$(totFolders)
a$(0,2) = UPPER$(x$(0,2))
a$(0,3) = x$(0,3)
a$(0,4) = STR$(rFiles1(path$, "", filter$, LEN(a$(0,3))+1, fi, di))
a$(0,5) = a$(0,2); a$(0,3)
END FUNCTION
FUNCTION rFiles1(path$, folderName$, filter$, rootLen, BYREF fi, BYREF di)
' recursively fills a$(), return value is total size of all files in folder
FILES path$; folderName$, filter$, x$()
numFiles = VAL(x$(0,0))
numFolders = VAL(x$(0,1))
IF numFiles > 0 THEN tmpIndex$ = STR$(fi + 1)
' copy file info
FOR count = 1 TO numFiles
fi += 1
a$(fi,0) = x$(count,0) ' file name
a$(fi,1) = x$(count,1) ' file size
a$(fi,2) = x$(count,2) ' date/time
a$(fi,3) = x$(count,3) ' attributes
a$(fi,4) = x$(count,4) ' date/time GMT
a$(fi,5) = MID$(x$(0,3),rootLen) ' path\to\
rFiles1 += VAL(x$(count,1)) ' total file size
NEXT count
' copy folder info
di += 1
a$(di,0) = folderName$ ' folder name
a$(di,1) = STR$(rFiles1) ' total file size
a$(di,2) = tmpIndex$ ' index to 1st file
a$(di,3) = x$(0,0) ' num of files
a$(di,4) = x$(0,1) ' num of folders
a$(di,5) = MID$(path$, rootLen+3) ' path\to
' save subfolder info and recurse
subPath$ = x$(0,2); x$(0,3)
FOR count = 1 TO numFolders
subFolders$ = subFolders$; x$(numFiles+count,1); ">"
NEXT count
FOR count = 1 TO numFolders
rFiles1 += rFiles1(subPath$,WORD$(subFolders$,count,">"),filter$,rootLen,fi,di)
NEXT count
END FUNCTION
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'NAME=lbbTree
'AUTHOR=CirothUngol
'ITEM=SUB lbbTree path$, filter$, BYREF a$(), mode
'DESCRIPTION=displays files/folders in a DOS TREE style format
SUB lbbTree path$, filter$, BYREF a$(), mode
' This function outputs a recursive folder tree similar to the DOS TREE command.
' path$ - The root folder to recursively search for files. If empty, StartupDir$ is assumed.
' filter$ - The file name to search for. Wildcards are allowed. If empty, "*" is assumed.
' a$() - 2D array passed BYREF is REDIMed and loaded with file/folder info.
' mode - An integer value to control the output:
' +0 is extended text mode.
' +1 is ascii text mode.
' +2 use alternate character set.
' +4 return only folders that contain files.
' +8 display file names in each folder.
' +16 display more file/folder info.
' +32 truncate display to 79 characters
' +64 half-sized margins
SELECT CASE mode MOD 4 ' /a + /c character sets
CASE 0
margin$ = " ;ÀÄÄÄ;³ ;ÃÄÄÄ"
IF mode AND 64 THEN margin$ = " ;ÀÄ;³ ;ÃÄ"
CASE 1
margin$ = " ;\---;| ;+---"
IF mode AND 64 THEN margin$ = " ;\-;| ;+-"
CASE 2
margin$ = " ;ÈÍÍÍ;º ;ÌÍÍÍ"
IF mode AND 64 THEN margin$ = " ;ÈÍ;º ;ÌÍ"
CASE 3
margin$ = " ;\___;| ;|___"
IF mode AND 64 THEN margin$ = " ;\_;| ;|_"
END SELECT
IF filter$ = "" THEN filter$ = "*"
di = rFiles(path$, filter$, a$())
tmp$ = a$(0,2); a$(0,3)
IF mode AND 8 THEN tmp$ += filter$ ' /f show filter$ if provided
IF mode AND 32 THEN tmp$ = LEFT$(tmp$,79)
PRINT tmp$;
IF mode AND 4 THEN ' /o only folders containing files
pi = di
IF lbbTree2(pi) = 0 THEN ' only the root folder found
PRINT
PRINT "No files found"
PRINT "No subfolders exist"
EXIT SUB
END IF
' remove marked folders from a$() and cascade down
ni = di ' new index
li = di + VAL(a$(0,1)) ' last index
FOR oi = di+1 TO li ' old index
IF a$(oi,0) <> "<" THEN
ni += 1
FOR i = 0 TO 5
a$(ni,i) = a$(oi,i)
NEXT i
END IF
NEXT oi
a$(0,1) = STR$(ni-di) ' new numFolders
END IF
CALL lbbTree1 fi, di, m$, fm$, dm$, mode, margin$
IF a$(0,1) = "1" THEN ' only the root folder
PRINT "No subfolders exist"
EXIT SUB
END IF
IF NOT(mode AND 16) THEN EXIT SUB ' not /m, so exit
tmp$ = TRIM$(USING("###,###,###,###,###",a$(0,4))); " bytes in "; TRIM$(USING("###,###,###",a$(0,0))); " files and "; TRIM$(USING("###,###,###",a$(0,1))); " folders"
PRINT LEFT$("--------------------------------------------------------------------------------", LEN(tmp$))
PRINT tmp$
END SUB
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
SUB lbbTree1 BYREF fi, BYREF di, m$, fm$, dm$, mode, margin$ ' recursively display a$()
di += 1 ' directory index
numFolders = VAL(a$(di, 4))
tmp$ = m$; dm$; a$(di,0)
IF mode AND 16 THEN tmp$ += " / "; a$(di,1); " / "; a$(di,3); " files / "; a$(di,4); " folders"
IF mode AND 32 THEN tmp$ = LEFT$(tmp$,79)
PRINT tmp$
IF mode AND 8 THEN ' /f display files
IF numFolders = 0 THEN fm2$ = WORD$(margin$,1,";")
IF numFolders > 0 THEN fm2$ = WORD$(margin$,3,";")
numFiles = VAL(a$(di,3))
FOR f = 1 TO numFiles
fi += 1 ' file index
tmp$ = m$; fm$; fm2$; a$(fi,0)
IF mode AND 16 THEN tmp$ += " / "; a$(fi,1); " / "; a$(fi,4)
IF mode AND 32 THEN tmp$ = LEFT$(tmp$,79)
PRINT tmp$
NEXT f
tmp$ = MID$(TRIM$("A";m$;fm$;fm2$),2)
IF mode AND 32 THEN tmp$ = LEFT$(tmp$,79)
IF numFiles > 0 THEN PRINT tmp$
END IF
IF fm$ <> "" THEN m$ = m$; fm$ ' if not the 1st recursion
FOR d = 1 TO numFolders
IF d = numFolders THEN
CALL lbbTree1 fi, di, m$, WORD$(margin$,1,";"), WORD$(margin$,2,";"), mode, margin$
ELSE
CALL lbbTree1 fi, di, m$, WORD$(margin$,3,";"), WORD$(margin$,4,";"), mode, margin$
END IF
NEXT d
END SUB
'''''''''''''''''''''
FUNCTION lbbTree2(BYREF pi) ' removes empty folders from the tree
pi += 1 ' progressive index
ri = pi ' root index
numFolders = VAL(a$(ri,4))
FOR d = 1 TO numFolders
IF lbbTree2(pi) = 0 THEN a$(ri,4) = STR$(VAL(a$(ri,4))-1) ' -1 folder
NEXT d
lbbTree2 = VAL(a$(ri,3)) + VAL(a$(ri,4)) ' numFiles + numFolders
IF lbbTree2 = 0 THEN a$(ri,0) = "<" ' mark folder for deletion
END FUNCTION
'''''''''''''''
SUB lbbTreeHelp ver$
ver$ = RIGHT$(" v";ver$, 18)
PRINT "Graphically displays the folder structure of a drive or path."; ver$
PRINT
PRINT "lbbTree [drive:][path] [/A] [/C] [/F] [/M] [/O] [/S filter] [/T] [/?]"
PRINT
PRINT " /A Use ASCII instead of extended characters."
PRINT " /C Use alternative character set."
PRINT " /F Display the names of the files in each folder."
PRINT " /L Use less spacing for the margins."
PRINT " /M Display more folder/file information."
PRINT " /O Display only folders that contain files."
PRINT " /S Search for file names matching filter. */? are allowed."
PRINT " /T Truncate display to 79 charaters per line."
PRINT " /? Display this help screen."
END
END SUB
|
|
Logged
|
LB Booster + LB Workshop + LB Builder = My Programs on Google Drive
|
|
|
|