;+ ; NAME: ; FindAllSubDirs ; PURPOSE: ; Return a list of all subdirectories in a specified directory ; CATEGORY: ; Environment ; CALLING SEQUENCE: FUNCTION FindAllSubDirs, Path, $ count = count , $ symlink = symlink , $ recursive = recursive , $ forcecd = ForceCD ; INPUTS: ; Path scalar; type: string; default: current directory ; OPTIONAL INPUT PARAMETERS: ; /symlink by default, symbolic links to directories are not returned ; unless /symlink is set (ignored on non-unix systems; ; see href=IsSymLink=. ; OUTPUTS: ; List array; type: string ; list of subdirectories ; fully-qualified directory names are returned. ; on Linux and Win32 the directories include the trailing (back)slash ; if no subdirectories are found then List = '' is returned. ; OPTIONAL OUTPUT PARAMETERS: ; count=count scalar; type: integer ; number of subdirectories ; INCLUDE: @compile_opt.pro ; On error, return to caller ; CALLS: ; InitVar, CheckDir, SetFileSpec, GetFileSpec, IsSymLink ; RESTRICTIONS: ; Currently linux, Win32 and vms are implemented. ; PROCEDURE: ; Findfile is used to get a list of files in the specified directories. Then the ; directories are selected. ; MODIFICATION HISTORY: ; AUG-2000, Paul Hick (UCSD/CASS) ; JUN-2001, Paul Hick (UCSD/CASS) ; added /symlink keyword ; JAN-2002, Paul Hick (UCSD/CASS) ; Return arg 'count' didn't exist on return if 'path' didn't exist. ; Now zero is returned. ; JUL-2002, Paul Hick (UCSD/CASS) ; Fixed a bug caused by peculiar behaviour of IDL findfile on Linux ; (and presumably every Unix flavor) when a directory is tested ; containing only a single subdirectory. This apparently reflects ; the same peculiar behaviour of the Unix 'ls' command. ; MAR-2003, Paul Hick (UCSD/CASS) ; Added /recursive keyword ; SEP-2006, Paul Hick (UCSD/CASS) ; Added some code to deal with spaces in directory names (adding ; explicit quotes). Moved initvar statement for Path to start of function. ; OCT-2006, Paul Hick (UCSD/CASS) ; Added forcecd keyword. ; JUL-2007, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; Replaced findfile by file_search (for unix only). Lot less complicated. ; Note that /forcecd is no longer used (and if set, is ignored). ;- InitVar, ForceCD , /key InitVar, recursive, /key IF n_elements(Path) EQ 0 THEN cd, current=Path IF recursive THEN BEGIN Sub = Path count = n_elements(Sub) ; Loop over all directories in Paths. We don't use a do loop because Paths will get updated ; inside the loop when /recursive is set. iSub = -1 REPEAT BEGIN ; Loop over all directories iSub = iSub+1 Path = filepath(root=strtrim(Sub[iSub],2),''); Add trailing delimiter ; Add directories to the list of directories already found Add = FindAllSubDirs(Path, count=iAdd, symlink=symlink, forcecd=ForceCD) IF iAdd NE 0 THEN BEGIN IF iSub LT count-1 THEN $ Sub = [Sub[0:iSub],Add,Sub[iSub+1:count-1]] $ ELSE $ Sub = [Sub[0:iSub],Add] count = count+iAdd ENDIF ENDREP UNTIL iSub EQ count-1 count = count-1 CASE count OF 0 : Sub = '' ELSE: Sub = Sub[1:*] ENDCASE RETURN, Sub ENDIF InitVar, symlink, /key Sub = '' count = 0 IF CheckDir(Path, LongPath) THEN BEGIN CASE strlowcase(!version.os_family) OF 'unix': BEGIN Files = file_search(LongPath+'/*',/mark_directory,/fully_qualify_path,count=count) ; Pick up all entries with a trailing slash ; (these are the directories). FOR i=0L,count-1 DO BEGIN IF strmid(Files[i],strlen(Files[i])-1,1) EQ '/' THEN BEGIN CASE symlink OF 0: IF NOT IsSymLink(Files[i]) THEN Sub = [Sub,Files[i]] 1: BEGIN Sub = [Sub,Files[i]] message, /info, 'descending into symlink: '+Files[0] END ENDCASE ENDIF ENDFOR count = n_elements(Sub)-1 IF count GT 0 THEN Sub = Sub[1:count] ;=========================== ; Old section using findfile ;------- ; The IDL findfile function apparently mimics the Unix ls ; command exactly. Both display weird behaviour when the ; directory tested contains only a single subdirectory (no ; other files), e.g. in the SolarSoft tree $SSW/gen has a ; single subdirectory $SSW/gen/idl, which in turn has a single ; subdirectory $SSW/gen/idl/ssw_system. ; findfile('/mnt/work/soft/ssw/gen/*') returns 'ssw_system', ; i.e. the 'idl' subdirectory is not mentioned at all, and ; hence we cannot reconstruct the content of $SSW/gen !!! ; If another file or directory would have been present (e.g. ; a file 'test.txt', then the findfile command returns: ; /mnt/work/soft/ssw/gen/test.txt /mnt/work/soft/ssw/gen/idl: ssw_system ; and, since we are using the trailing colon to identify ; directories, all is well. ; We intercept this funny special case using a findfile call ; without a wildcard. ;Files = findfile('"'+LongPath+'"', count=count) ;CASE count OF ;0: ; Empty directory: nothing to do ;1: BEGIN ; One entry only ; Files = filepath( root=LongPath, Files[0] ) ; count = CheckDir(Files, silent=1) ; CASE count OF ; 0: Files = '' ; Single entry is NOT a directory ; 1: Files = Files+':' ; Single entry is a directory ; ENDCASE ;END ;ELSE: BEGIN ; tmp = LongPath ; i = strlen(tmp)-1 ; Strip trailing slash ; IF strmid(tmp,i,1) EQ '/' THEN tmp = strmid(tmp,0,i) ; CASE ForceCD OF ; 0: Files = findfile( filepath(root='"'+tmp+'"', '*'), count=count ) ; 1: BEGIN ; cd, tmp, current=current ; Files = findfile('*',count=count) ; cd, current ; IF count GT 0 THEN Files = filepath(root=tmp,Files) ; END ; ENDCASE ;END ;ENDCASE ;FOR i=0L,count-1 DO BEGIN ; tmp = strlen(Files[i]) ; IF strmid(Files[i], tmp-1,1) EQ ':' THEN BEGIN ; tmp = strmid(Files[i],0,tmp-1) ; CASE symlink OF ; 0: IF NOT IsSymLink(tmp) THEN Sub = [Sub, tmp] ; 1: BEGIN ; Sub = [Sub, tmp] ; message, /info, 'descending into symlink: '+tmp[0] ; END ; ENDCASE ; ENDIF ;ENDFOR ;count = n_elements(Sub)-1 ;IF count GT 0 THEN Sub = Sub[1:count]+'/' ;============================== END 'windows': BEGIN Files = findfile( filepath(root=LongPath, '*'), count=count ) i = where( strpos(Files,'\.\') EQ -1 AND strpos(Files,'\..\') EQ -1, count ) IF count GT 0 THEN BEGIN Files = Files[i] FOR i=0,count-1 DO IF strmid(Files[i], strlen(Files[i])-1,1) EQ '\' THEN Sub = [Sub, Files[i]] ENDIF count = n_elements(Sub)-1 IF count GT 0 THEN Sub = Sub[1:count] END 'vms': BEGIN Files = findfile( filepath(root=LongPath, '*.DIR'), count=count) IF count GT 0 THEN BEGIN SetFileSpec, Files Sub = GetFileSpec(upto='directory') FOR i=0,count-1 DO Sub[i] = strmid(Sub[i],0,strlen(Sub[i])-1) Sub = Sub+'.'+GetFileSpec(from='name',upto='name')+']' ENDIF END ENDCASE ENDIF RETURN, Sub & END