- DIRS_LIST_RECURSIVE(dir$)
- FILES_LIST_RECURSIVE(dir$)
Code: Select all
{{/lib/files/list_recursive}}    ' whatever you name it and wherever you place it
SET OUTPUT FONT SIZE 14
' List all directories recursively starting from Smart Basic's root directory
dir$ = "/"
DIRS_LIST_RECURSIVE(dir$)
PRINT "All dirs starting at """ & dir$ & """"
PRINT "(" & DIRS_LIST_RECURSIVE.nDirs & " Found)"
FOR i = 0 TO DIRS_LIST_RECURSIVE.nDirs-1
  PRINT DIRS_LIST_RECURSIVE.dirs$(i)
NEXT i
PRINT ""
 ' List all files recursively starting one level above the current directory
dir$ = ".."
FILES_LIST_RECURSIVE(dir$)
PRINT "All files starting in """ & dir$ & """"
PRINT "(" & FILES_LIST_RECURSIVE.nFiles & " Found)"
FOR i = 0 TO FILES_LIST_RECURSIVE.nFiles-1
  PRINT FILES_LIST_RECURSIVE.files$(i)
NEXT i
' Example of how to copy the resulting array into a local scope
nFiles = FILES_LIST_RECURSIVE.nFiles
DIM files$(nFiles)
COPY1$(FILES_LIST_RECURSIVE.files$, files$)You can also write to an array named OPT.dirs_exclude$() and populate it with directory paths that you want to exclude from the searches. For example, I have a /Backups folder that is large and has archived code that I'm not interested in seeing all of its subfolders. This exclude functionality is more useful for performing find and replaces recursively, but that is a separate library file. If anyone is interested I can also put that here on the forum.
Here is the library:
Code: Select all
'g'
/*=============================================================
Functions:
Functions for recursively listing all files or folders in all subdirectories:
    DIRS_LIST_RECURSIVE(dir$)
    FILES_LIST_RECURSIVE(dir$)
Functions for managing the list of directories to exclude from list recursive operations:
    CLEAR_EXCLUDE_DIRS()
    DEFAULT_EXCLUDE_DIRS()
Parameters:
    OPT.dirs_exclude$()
===============================================================
For both DIRS_LIST_RECURSIVE and FILES_LIST_RECURSIVE, the directories listed in OPT.dirs_exclude$() will be ignored, unless it is the directory provided to the function (input dir$).
For each functions' output arrays, DIRS_LIST_RECURSIVE.dirs$() and FILES_LIST_RECURSIVE.files$(), each item is a folder or file path. This path is relative to the input directory. For example, an input of ".." (the directory up one level) will result in an array will all elements beginning with "../". Note however that the default OPT.dirs_exclude$ list are absolute paths that begin at the root directory, "/". Overwrite this list of directories to exclude if needed.
===============================================================
DIRS_LIST_RECURSIVE creates a one-dimensional array that lists all folders within the specified folder and recursively down all of its subfolders. This list includes the input directory itself.
  Inputs:
    dir$    Directory to recursively traverse
  Outputs:
    DIRS_LIST_RECURSIVE.dirs$()    Array of dir paths
    DIRS_LIST_RECURSIVE.nDirs      Size of dirs$()
===============================================================
FILES_LIST_RECURSIVE creates a one-dimensional array that lists all files within the specified folder and recursively down all of its subfolders.
  Inputs:
    dir$    Directory to recursively traverse
  Outputs:
    FILES_LIST_RECURSIVE.files$()    Array of file paths
    FILES_LIST_RECURSIVE.nFiles      Size of files$()
=============================================================*/
''
'b'
'==============================================================
'  Variable initialization
'==============================================================
''
DEFAULT_EXCLUDE_DIRS()
.ERR = -1
.OK = 0
DIM BF.s1$(1000)
BF_RESIZE_S1.resizeFactor = 5
'b'
'==============================================================
'  Functions
'==============================================================
''
DEF CLEAR_EXCLUDE_DIRS ()
  DIM OPT.dirs_exclude$(1)
END DEF
'==============================================================
DEF DEFAULT_EXCLUDE_DIRS ()
'c' Only these DATA statements need to be changed (a minimum of one DATA statement is required)
  DATA ""
  'DATA "/Backups"
  'DATA "/Data"
  '... etc.
''
  n = 0
  WHILE DATA_EXIST()
    READ dir$
    n += 1
  END WHILE
  RESTORE
  DIM OPT.dirs_exclude$(n)
  FOR i = 0 TO n-1
    READ dir$
    IF NOT ENDS_WITH(dir$,"/") THEN dir$ &= "/"
    OPT.dirs_exclude$(i) = dir$
  NEXT i
END DEF
'==============================================================
DEF DIRS_LIST_RECURSIVE (dir$)
  nDirs = 0       ' Init in case of error
  DIM dirs$(1)
  IF NOT IS_DIR(dir$) THEN RETURN .ERR
  IF NOT ENDS_WITH(dir$,"/") THEN dir$ &= "/"
  GET DIM BF.s1$ XSIZE bufSz
  BF.s1$(0) = dir$
  iRead = 0
  iWrite = 1
  DO
    DIR BF.s1$(iRead) LIST DIRS dirs$, n
    IF iWrite+n > bufSz THEN bufSz = BF_RESIZE_S1(iWrite+n)
    FOR i = 0 TO n-1
      dir$ = BF.s1$(iRead) & dirs$(i) & "/"
      IF MATCH(OPT.dirs_exclude$, dir$) > -1 THEN CONTINUE i
      BF.s1$(iWrite) = dir$
      iWrite += 1
    NEXT i
    iRead += 1
  UNTIL iRead >= iWrite
  nDirs = iWrite
  DIM dirs$(nDirs)
  COPY1$(BF.s1$, dirs$)
  SORT dirs$
  RETURN .OK
END DEF
'==============================================================
DEF FILES_LIST_RECURSIVE (dir$)
  nFiles = 0       ' Init in case of error
  DIM files$(1)
  IF NOT IS_DIR(dir$) THEN RETURN .ERR
  DIRS_LIST_RECURSIVE(dir$)
  GET DIM BF.s1$ XSIZE bufSz
  iWrite = 0
  FOR iRead = 0 TO DIRS_LIST_RECURSIVE.nDirs-1
    dir$ = DIRS_LIST_RECURSIVE.dirs$(iRead)
    DIR dir$ LIST FILES files$, n
    IF iWrite+n > bufSz THEN bufSz = BF_RESIZE_S1(iWrite+n)
    FOR i = 0 TO n-1
      BF.s1$(iWrite) = dir$ & files$(i)
      iWrite += 1
    NEXT i
  NEXT iRead
  nFiles = iWrite
  IF nFiles > 0 THEN
    DIM files$(nFiles)
    COPY1$(BF.s1$, files$)
    SORT files$
  ELSE
    DIM files$(1)
  END IF
  RETURN .OK
END DEF
'b'
'==============================================================
'  Other Functions
'==============================================================
''
DEF IS_FILE (path$)
  IF NOT FILE_EXISTS(path$) THEN RETURN .FALSE
  IF INSTR(path$, "/") = -1 THEN
    dir$ = "."
    file$ = path$
  ELSE
    idxFilename = LEN(path$) - INSTR(REVERSE$(path$), "/")
    dir$ = LEFT$(path$, idxFilename)
    file$ = RIGHT$(path$, LEN(path$)-idxFilename)
  END IF
  DIR dir$ LIST FILES files$, nFiles
  IF MATCH(files$, file$) = -1 THEN RETURN .FALSE
  RETURN .TRUE
END DEF
'==============================================================
DEF IS_DIR (path$)
  IF path$ = "" THEN RETURN .TRUE       ' Equivalent to "."
  IF IS_FILE(path$) THEN RETURN .FALSE
  IF NOT FILE_EXISTS(path$) THEN RETURN .FALSE
  RETURN .TRUE
END DEF
'==============================================================
DEF BF_RESIZE_S1 (minSize)
  GET DIM BF.s1$ XSIZE bufSize
  DIM TEMP.a$(bufSize)
  COPY1$(BF.s1$, TEMP.a$)
  DO bufSize *= resizeFactor
  UNTIL bufSize >= minSize
  DIM BF.s1$(bufSize)
  COPY1$(TEMP.a$, BF.s1$)
  RETURN bufSize
END DEF
'==============================================================
DEF COPY1$ (from$(), to$())
  GET DIM from$ XSIZE n
  GET DIM to$ XSIZE m
  n = MIN(n,m)
  FOR i = 0 TO n-1
    to$(i) = from$(i)
  NEXT i
END DEF
'==============================================================
DEF MATCH (array$(), string$)
  GET DIM array$ XSIZE n
  FOR i = 0 TO n-1
    IF array$(i) = string$ THEN RETURN i
  NEXT i
  RETURN -1    ' string$ not found (this is not an error)
END DEF
'==============================================================
DEF ENDS_WITH (str$, end$)
  IF RIGHT$(str$,LEN(end$)) = end$ THEN RETURN 1 ELSE RETURN 0
END DEF
'==============================================================
