############################################################################ # # File: gdl2.icn # # Subject: Procedures to get directory lists # # Authors: Richard L. Goerwitz and Charles Shartsis # # Date: August 14, 1995 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # Version: 1.3+ # ############################################################################ # # Gdl returns a list containing everything in a directory (whose name # must be passed as an argument to gdl). Nothing fancy. I use this file # as a template, modifying the procedures according to the needs of the # program in which they are used. # # NOTE: MSDOS results are all in lower case # # Modifications: # 1) Fixed MSDOS routines. # 2) Added gdlrec which does same thing as gdl except it recursively descends # through subdirectories. May choose which Unix utility to use by passing # in method parameter. See below. # ############################################################################ # # Requires: UNIX or MS-DOS # ############################################################################ procedure gdl(dir) local getdir getdir := set_getdir_by_os() return getdir(dir) end procedure gdlrec(dir, method) # Unix method to use: &null for compatibility (uses "/bin/ls"), # not null for speed (uses "find") local getdir getdir := set_getdir_rec_by_os(method) return getdir(dir) end procedure set_getdir_by_os() # Decide how to get a directory, based on whether we are running # under Unix or MS-DOS. if find("UNIX", &features) then return unix_get_dir else if find("MS-DOS", &features) then return msdos_get_dir else stop("Your operating system is not (yet) supported.") end procedure set_getdir_rec_by_os(method) # Decide how to get a directory, based on whether we are running # under Unix or MS-DOS. if find("UNIX", &features) then { if /method then return unix_get_dir_rec else return unix_get_dir_rec2 } else if find("MS-DOS", &features) then return msdos_get_dir_rec else stop("Your operating system is not (yet) supported.") end procedure msdos_get_dir(dir) # Returns a sorted list of all filenames (full paths included) in # directory "dir." The list is sorted. Fails on invalid or empty # directory. Aborts if temp file cannot be opened. # # Temp files can be directed to one or another directory either by # manually setting the variable temp_dir below, or by setting the # value of the environment variable TEMPDIR to an appropriate # directory name. local in_dir, filename_list, line, temp_name, filename static temp_dir initial { temp_dir := (trim(map(getenv("TEMPDIR"), "/", "\\"), '\\') || "\\") | ".\\" } # Get name of tempfile to be used. temp_name := get_dos_tempname(temp_dir) | stop("No more available tempfile names!") ### Added by C. Shartsis 9/19/94 # Make implicit current directory explicit # Otherwise current and root directory get mapped to same thing if (dir == "") | (dir ? (tab(any(&letters)) & =":" & pos(0)) ) then dir ||:= "." # Make sure we have an unambiguous directory name, with backslashes # instead of Unix-like forward slashes. dir := trim(map(dir, "/", "\\"), '\\') ### Added by C. Shartsis 9/19/94 # Put backslash back on if dir is the root directory # Otherwise the current directory is returned if (dir == "") | (dir ? (tab(any(&letters)) & =":" & pos(0)) ) then dir ||:= "\\" # Put dir listing into a temp file. system("dir "||dir||" > "||temp_name) # Put tempfile entries into a list, removing blank- and # space-initial lines. Exclude directories (i.e. return file # names only). in_dir := open(temp_name,"r") | stop("Can't open temp file in directory ",temp_dir,".") filename_list := list() every filename := ("" ~== !in_dir) do { match(" ",filename) | find(" ", filename) & next # Exclude our own tempfiles (may not always be appropriate). filename ?:= trim(trim(tab(10)) || "." || tab(13), '. ') ### Change: C. Shartsis - 4/9/95 # Exclude tempfile if filename ? ( ="ICONDIR." & tab(any(&digits)) & tab(any(&digits)) & tab(any(&digits)) ) then next ### Change: C. Shartsis - 9/19/94 # Otherwise file f in directory c:\d comes out as "c:\df" instead of "c:\d\f" #put(filename_list, map(dir || filename)) put(filename_list, map(trim(dir, '\\') || "\\" || filename)) } # Clean up. close(in_dir) & remove(temp_name) # Check to be sure we actually managed to read some files. if *filename_list = 0 then fail else return sort(filename_list) end procedure msdos_get_dir_rec(dir, level) # Returns a sorted list of all filenames (full paths included) in # directory "dir." The list is sorted. Fails on invalid or empty # directory. Aborts if temp file cannot be opened. # # Temp files can be directed to one or another directory either by # manually setting the variable temp_dir below, or by setting the # value of the environment variable TEMPDIR to an appropriate # directory name. local in_dir, line, filename, raw_list local tmp_filelist, tmp_dirlist static temp_dir, temp_name, filename_list initial { temp_dir := (trim(map(getenv("TEMPDIR"), "/", "\\"), '\\') || "\\") | ".\\" } # Establish recursion level /level := 0 if level = 0 then { filename_list := list() # Get name of tempfile to be used. temp_name := get_dos_tempname(temp_dir) | stop("No more available tempfile names!") } # Make implicit current directory explicit # Otherwise current and root directory get mapped to same thing if (dir == "") | (dir ? (tab(any(&letters)) & =":" & pos(0)) ) then dir ||:= "." # Make sure we have an unambiguous directory name, with backslashes # instead of Unix-like forward slashes. dir := trim(map(dir, "/", "\\"), '\\') # Put backslash back on if dir is the root directory # Otherwise the current directory is returned if (dir == "") | (dir ? (tab(any(&letters)) & =":" & pos(0)) ) then dir ||:= "\\" # Put dir listing into a temp file. system("dir "||dir||" > "||temp_name) # Put tempfile entries into a list, removing blank- and # space-initial lines. Exclude directories (i.e. return file # names only). in_dir := open(temp_name,"r") | stop("Can't open temp file in directory ",temp_dir,".") raw_list := [] every put(raw_list, !in_dir) # Clean up. close(in_dir) & remove(temp_name) tmp_dirlist := [] tmp_filelist := [] every filename := ("" ~== !raw_list) do { match(" ",filename) | match(".",filename) & next # Process Directories if find(" ", filename) then { filename ?:= tab(many(~' \t')) put(tmp_dirlist, map(trim(dir, '\\') || "\\" || filename)) } # Save files to list else { # extract the file name filename ?:= trim(trim(tab(10)) || "." || tab(13), '. ') # Exclude tempfile if not (filename ? ( ="ICONDIR." & tab(any(&digits)) & tab(any(&digits)) & tab(any(&digits)) )) then # Otherwise file f in directory c:\d comes out as "c:\df" instead of "c:\d\f" put(tmp_filelist, map(trim(dir, '\\') || "\\" || filename)) } } # Add files to master list every put(filename_list, !sort(tmp_filelist)) # Process remaining directories every msdos_get_dir_rec(!sort(tmp_dirlist), level + 1) # Check to be sure we actually managed to read some files. if level = 0 then { if *filename_list = 0 then fail else return filename_list } end procedure get_dos_tempname(dir) local temp_name, temp_file # Don't clobber existing files. Get a unique temp file name for # use as a temporary storage site. every temp_name := dir || "icondir." || right(string(1 to 999),3,"0") do { temp_file := open(temp_name,"r") | break close(temp_file) } return \temp_name end procedure unix_get_dir(dir) local filename_list, in_dir, filename dir := trim(dir, '/') || "/" filename_list := list() in_dir := open("/bin/ls -F "||dir, "pr") every filename := ("" ~== !in_dir) do { match("/",filename,*filename) & next put(filename_list, trim(dir || filename, '*')) } close(in_dir) if *filename_list = 0 then fail else return filename_list end procedure unix_get_dir_rec(dir, level) # Returns a sorted list of all filenames (full paths included) in # directory "dir." The list is sorted. Fails on invalid or empty # directory. Aborts if temp file cannot be opened. local in_dir, filename, raw_list, cmd local tmp_filelist, tmp_dirlist static filename_list # Establish recursion level /level := 0 if level = 0 then filename_list := list() # Append trailing slash dir := trim(dir, '/') || "/" # Put tempfile entries into a list, removing blank- and # space-initial lines. Exclude directories (i.e. return file # names only). cmd := "/bin/ls -FL " || dir in_dir := open(cmd,"pr") | stop(cmd, " will not run on this system") raw_list := [] every put(raw_list, !in_dir) # Clean up. close(in_dir) tmp_dirlist := [] tmp_filelist := [] every filename := ("" ~== !raw_list) do { if match(" ",filename) | match(".",filename) | filename[-1] == "=" then next if filename[-1] == "*" then filename := filename[1:-1] # Process Directories if filename[-1] == "/" then put(tmp_dirlist, dir || filename) # Save files to list else put(tmp_filelist, dir || filename) } # Add files to master list every put(filename_list, !sort(tmp_filelist)) # Process remaining directories every unix_get_dir_rec(!sort(tmp_dirlist), level + 1) # Check to be sure we actually managed to read some files. if level = 0 then { if *filename_list = 0 then fail else return filename_list } end # This works too. # This routine is faster but depends on the Unix "find" program. # Don't know if all Unixes have this. procedure unix_get_dir_rec2(dir) local filename_list, in_dir, cmd dir := trim(dir, '/') || "/" filename_list := list() cmd := "find " || dir || " -type f -print" in_dir := open(cmd, "pr") | stop(cmd, " will not run on this system") every put(filename_list, !in_dir) close(in_dir) if *filename_list = 0 then fail else return filename_list end