1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2004 Kris Bell. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6 
7         version:        Jun 2004: Initial release
8         version:        Dec 2006: Pacific release
9 
10         author:         Kris
11 
12 *******************************************************************************/
13 
14 deprecated("tango.io.FileScan is deprecated. Please use tango.io.FilePath.toList or tango.io.vfs.* instead.") module tango.io.FileScan;
15 
16 
17 
18 public  import tango.io.FilePath;
19 
20 private import tango.core.Exception;
21 
22 /*******************************************************************************
23     This module is deprecated because it doesn't support file globbing
24     or regexes for matching files and because it ignores folders that
25     it doesn't recurse into (a non-recursive scan will never return any
26     folders).
27 
28         Recursively scan files and directories, adding filtered files to
29         an output structure as we go. This can be used to produce a list
30         of subdirectories and the files contained therein. The following
31         example lists all files with suffix ".d" located via the current
32         directory, along with the folders containing them:
33         ---
34         auto scan = new FileScan;
35 
36         scan (".", ".d");
37 
38         Stdout.formatln ("{} Folders", scan.folders.length);
39         foreach (folder; scan.folders)
40                  Stdout.formatln ("{}", folder);
41 
42         Stdout.formatln ("\n{} Files", scan.files.length);
43         foreach (file; scan.files)
44                  Stdout.formatln ("{}", file);
45         ---
46 
47         This is unlikely the most efficient method to scan a vast number of
48         files, but operates in a convenient manner.
49 
50 *******************************************************************************/
51 
52 class FileScan
53 {
54         alias sweep     opCall;
55 
56         FilePath[]      fileSet;
57         const(char)[][]        errorSet;
58         FilePath[]      folderSet;
59 
60         /***********************************************************************
61 
62             Alias for Filter delegate. Accepts a FilePath & a bool as
63             arguments and returns a bool.
64 
65             The FilePath argument represents a file found by the scan,
66             and the bool whether the FilePath represents a folder.
67 
68             The filter should return true, if matched by the filter. Note
69             that returning false where the path is a folder will result
70             in all files contained being ignored. To always recurse folders,
71             do something like this:
72             ---
73             return (isDir || match (fp.name));
74             ---
75 
76         ***********************************************************************/
77 
78         alias FilePath.Filter Filter;
79 
80        /***********************************************************************
81 
82                 Return all the errors found in the last scan
83 
84         ***********************************************************************/
85 
86         public const(char)[][] errors ()
87         {
88                 return errorSet;
89         }
90 
91         /***********************************************************************
92 
93                 Return all the files found in the last scan
94 
95         ***********************************************************************/
96 
97         public FilePath[] files ()
98         {
99                 return fileSet;
100         }
101 
102         /***********************************************************************
103 
104                 Return all directories found in the last scan
105 
106         ***********************************************************************/
107 
108         public FilePath[] folders ()
109         {
110                 return folderSet;
111         }
112 
113         /***********************************************************************
114 
115                 Sweep a set of files and directories from the given parent
116                 path, with no filtering applied
117 
118         ***********************************************************************/
119 
120         FileScan sweep (const(char)[] path, bool recurse=true)
121         {
122                 return sweep (path, cast(Filter) null, recurse);
123         }
124 
125         /***********************************************************************
126 
127                 Sweep a set of files and directories from the given parent
128                 path, where the files are filtered by the given suffix
129 
130         ***********************************************************************/
131 
132         FileScan sweep (const(char)[] path, const(char)[] match, bool recurse=true)
133         {
134                 return sweep (path, (FilePath fp, bool isDir)
135                              {return isDir || fp.suffix == match;}, recurse);
136         }
137 
138         /***********************************************************************
139 
140                 Sweep a set of files and directories from the given parent
141                 path, where the files are filtered by the provided delegate
142 
143         ***********************************************************************/
144 
145         FileScan sweep (const(char)[] path, Filter filter, bool recurse=true)
146         {
147                 errorSet = null, fileSet = folderSet = null;
148                 /* Bad dup */
149                 return scan (new FilePath(path.dup), filter, recurse);
150         }
151 
152         /***********************************************************************
153 
154                 Internal routine to locate files and sub-directories. We
155                 skip entries with names composed only of '.' characters.
156 
157         ***********************************************************************/
158 
159         private FileScan scan (FilePath folder, Filter filter, bool recurse)
160         {
161                 try {
162                     auto paths = folder.toList (filter);
163 
164                     auto count = fileSet.length;
165                     foreach (path; paths)
166                              if (! path.isFolder)
167                                    fileSet ~= path;
168                              else
169                                 if (recurse)
170                                     scan (path, filter, recurse);
171 
172                     // add packages only if there's something in them
173                     if (fileSet.length > count)
174                         folderSet ~= folder;
175 
176                     } catch (IOException e)
177                              errorSet ~= e.toString();
178                 return this;
179         }
180 }
181 
182 
183 /*******************************************************************************
184 
185 *******************************************************************************/
186 
187 debug (FileScan)
188 {
189         import tango.io.Stdout;
190 
191         void main()
192         {
193                 auto scan = new FileScan;
194 
195                 scan (".");
196 
197                 Stdout.formatln ("{} Folders", scan.folders.length);
198                 foreach (folder; scan.folders)
199                          Stdout (folder).newline;
200 
201                 Stdout.formatln ("\n{} Files", scan.files.length);
202                 foreach (file; scan.files)
203                          Stdout (file).newline;
204 
205                 Stdout.formatln ("\n{} Errors", scan.errors.length);
206                 foreach (error; scan.errors)
207                          Stdout (error).newline;
208         }
209 }