' 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
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' '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