comparison tango/tango/io/FileScan.d @ 132:1700239cab2e trunk

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