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