]>
Commit | Line | Data |
---|---|---|
1 | /////////////////////////////////////////////////////////////////////////////// | |
2 | // Name: src/common/dircmn.cpp | |
3 | // Purpose: wxDir methods common to all implementations | |
4 | // Author: Vadim Zeitlin | |
5 | // Modified by: | |
6 | // Created: 19.05.01 | |
7 | // Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> | |
8 | // Licence: wxWindows licence | |
9 | /////////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | // ============================================================================ | |
12 | // declarations | |
13 | // ============================================================================ | |
14 | ||
15 | // ---------------------------------------------------------------------------- | |
16 | // headers | |
17 | // ---------------------------------------------------------------------------- | |
18 | ||
19 | // For compilers that support precompilation, includes "wx.h". | |
20 | #include "wx/wxprec.h" | |
21 | ||
22 | #ifdef __BORLANDC__ | |
23 | #pragma hdrstop | |
24 | #endif | |
25 | ||
26 | #ifndef WX_PRECOMP | |
27 | #include "wx/string.h" | |
28 | #include "wx/log.h" | |
29 | #include "wx/intl.h" | |
30 | #include "wx/filefn.h" | |
31 | #include "wx/arrstr.h" | |
32 | #endif //WX_PRECOMP | |
33 | ||
34 | #include "wx/dir.h" | |
35 | #include "wx/filename.h" | |
36 | ||
37 | // ============================================================================ | |
38 | // implementation | |
39 | // ============================================================================ | |
40 | ||
41 | // ---------------------------------------------------------------------------- | |
42 | // wxDirTraverser | |
43 | // ---------------------------------------------------------------------------- | |
44 | ||
45 | wxDirTraverseResult | |
46 | wxDirTraverser::OnOpenError(const wxString& WXUNUSED(dirname)) | |
47 | { | |
48 | return wxDIR_IGNORE; | |
49 | } | |
50 | ||
51 | // ---------------------------------------------------------------------------- | |
52 | // wxDir::HasFiles() and HasSubDirs() | |
53 | // ---------------------------------------------------------------------------- | |
54 | ||
55 | // dumb generic implementation | |
56 | ||
57 | bool wxDir::HasFiles(const wxString& spec) const | |
58 | { | |
59 | wxString s; | |
60 | return GetFirst(&s, spec, wxDIR_FILES | wxDIR_HIDDEN); | |
61 | } | |
62 | ||
63 | // we have a (much) faster version for Unix | |
64 | #if (defined(__CYGWIN__) && defined(__WINDOWS__)) || !defined(__UNIX_LIKE__) || defined(__EMX__) || defined(__WINE__) | |
65 | ||
66 | bool wxDir::HasSubDirs(const wxString& spec) const | |
67 | { | |
68 | wxString s; | |
69 | return GetFirst(&s, spec, wxDIR_DIRS | wxDIR_HIDDEN); | |
70 | } | |
71 | ||
72 | #endif // !Unix | |
73 | ||
74 | // ---------------------------------------------------------------------------- | |
75 | // wxDir::GetNameWithSep() | |
76 | // ---------------------------------------------------------------------------- | |
77 | ||
78 | wxString wxDir::GetNameWithSep() const | |
79 | { | |
80 | // Note that for historical reasons (i.e. because GetName() was there | |
81 | // first) we implement this one in terms of GetName() even though it might | |
82 | // actually make more sense to reverse this logic. | |
83 | ||
84 | wxString name = GetName(); | |
85 | if ( !name.empty() ) | |
86 | { | |
87 | // Notice that even though GetName() isn't supposed to return the | |
88 | // separator, it can still be present for the root directory name. | |
89 | if ( name.Last() != wxFILE_SEP_PATH ) | |
90 | name += wxFILE_SEP_PATH; | |
91 | } | |
92 | ||
93 | return name; | |
94 | } | |
95 | ||
96 | // ---------------------------------------------------------------------------- | |
97 | // wxDir::Traverse() | |
98 | // ---------------------------------------------------------------------------- | |
99 | ||
100 | size_t wxDir::Traverse(wxDirTraverser& sink, | |
101 | const wxString& filespec, | |
102 | int flags) const | |
103 | { | |
104 | wxCHECK_MSG( IsOpened(), (size_t)-1, | |
105 | wxT("dir must be opened before traversing it") ); | |
106 | ||
107 | // the total number of files found | |
108 | size_t nFiles = 0; | |
109 | ||
110 | // the name of this dir with path delimiter at the end | |
111 | const wxString prefix = GetNameWithSep(); | |
112 | ||
113 | // first, recurse into subdirs | |
114 | if ( flags & wxDIR_DIRS ) | |
115 | { | |
116 | wxString dirname; | |
117 | for ( bool cont = GetFirst(&dirname, wxEmptyString, | |
118 | (flags & ~(wxDIR_FILES | wxDIR_DOTDOT)) | |
119 | | wxDIR_DIRS); | |
120 | cont; | |
121 | cont = cont && GetNext(&dirname) ) | |
122 | { | |
123 | const wxString fulldirname = prefix + dirname; | |
124 | ||
125 | switch ( sink.OnDir(fulldirname) ) | |
126 | { | |
127 | default: | |
128 | wxFAIL_MSG(wxT("unexpected OnDir() return value") ); | |
129 | // fall through | |
130 | ||
131 | case wxDIR_STOP: | |
132 | cont = false; | |
133 | break; | |
134 | ||
135 | case wxDIR_CONTINUE: | |
136 | { | |
137 | wxDir subdir; | |
138 | ||
139 | // don't give the error messages for the directories | |
140 | // which we can't open: there can be all sorts of good | |
141 | // reason for this (e.g. insufficient privileges) and | |
142 | // this shouldn't be treated as an error -- instead | |
143 | // let the user code decide what to do | |
144 | bool ok; | |
145 | do | |
146 | { | |
147 | wxLogNull noLog; | |
148 | ok = subdir.Open(fulldirname); | |
149 | if ( !ok ) | |
150 | { | |
151 | // ask the user code what to do | |
152 | bool tryagain; | |
153 | switch ( sink.OnOpenError(fulldirname) ) | |
154 | { | |
155 | default: | |
156 | wxFAIL_MSG(wxT("unexpected OnOpenError() return value") ); | |
157 | // fall through | |
158 | ||
159 | case wxDIR_STOP: | |
160 | cont = false; | |
161 | // fall through | |
162 | ||
163 | case wxDIR_IGNORE: | |
164 | tryagain = false; | |
165 | break; | |
166 | ||
167 | case wxDIR_CONTINUE: | |
168 | tryagain = true; | |
169 | } | |
170 | ||
171 | if ( !tryagain ) | |
172 | break; | |
173 | } | |
174 | } | |
175 | while ( !ok ); | |
176 | ||
177 | if ( ok ) | |
178 | { | |
179 | nFiles += subdir.Traverse(sink, filespec, flags); | |
180 | } | |
181 | } | |
182 | break; | |
183 | ||
184 | case wxDIR_IGNORE: | |
185 | // nothing to do | |
186 | ; | |
187 | } | |
188 | } | |
189 | } | |
190 | ||
191 | // now enum our own files | |
192 | if ( flags & wxDIR_FILES ) | |
193 | { | |
194 | flags &= ~wxDIR_DIRS; | |
195 | ||
196 | wxString filename; | |
197 | bool cont = GetFirst(&filename, filespec, flags); | |
198 | while ( cont ) | |
199 | { | |
200 | wxDirTraverseResult res = sink.OnFile(prefix + filename); | |
201 | if ( res == wxDIR_STOP ) | |
202 | break; | |
203 | ||
204 | wxASSERT_MSG( res == wxDIR_CONTINUE, | |
205 | wxT("unexpected OnFile() return value") ); | |
206 | ||
207 | nFiles++; | |
208 | ||
209 | cont = GetNext(&filename); | |
210 | } | |
211 | } | |
212 | ||
213 | return nFiles; | |
214 | } | |
215 | ||
216 | // ---------------------------------------------------------------------------- | |
217 | // wxDir::GetAllFiles() | |
218 | // ---------------------------------------------------------------------------- | |
219 | ||
220 | class wxDirTraverserSimple : public wxDirTraverser | |
221 | { | |
222 | public: | |
223 | wxDirTraverserSimple(wxArrayString& files) : m_files(files) { } | |
224 | ||
225 | virtual wxDirTraverseResult OnFile(const wxString& filename) | |
226 | { | |
227 | m_files.push_back(filename); | |
228 | return wxDIR_CONTINUE; | |
229 | } | |
230 | ||
231 | virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) | |
232 | { | |
233 | return wxDIR_CONTINUE; | |
234 | } | |
235 | ||
236 | private: | |
237 | wxArrayString& m_files; | |
238 | ||
239 | wxDECLARE_NO_COPY_CLASS(wxDirTraverserSimple); | |
240 | }; | |
241 | ||
242 | /* static */ | |
243 | size_t wxDir::GetAllFiles(const wxString& dirname, | |
244 | wxArrayString *files, | |
245 | const wxString& filespec, | |
246 | int flags) | |
247 | { | |
248 | wxCHECK_MSG( files, (size_t)-1, wxT("NULL pointer in wxDir::GetAllFiles") ); | |
249 | ||
250 | size_t nFiles = 0; | |
251 | ||
252 | wxDir dir(dirname); | |
253 | if ( dir.IsOpened() ) | |
254 | { | |
255 | wxDirTraverserSimple traverser(*files); | |
256 | ||
257 | nFiles += dir.Traverse(traverser, filespec, flags); | |
258 | } | |
259 | ||
260 | return nFiles; | |
261 | } | |
262 | ||
263 | // ---------------------------------------------------------------------------- | |
264 | // wxDir::FindFirst() | |
265 | // ---------------------------------------------------------------------------- | |
266 | ||
267 | class wxDirTraverserFindFirst : public wxDirTraverser | |
268 | { | |
269 | public: | |
270 | wxDirTraverserFindFirst() { } | |
271 | ||
272 | virtual wxDirTraverseResult OnFile(const wxString& filename) | |
273 | { | |
274 | m_file = filename; | |
275 | return wxDIR_STOP; | |
276 | } | |
277 | ||
278 | virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) | |
279 | { | |
280 | return wxDIR_CONTINUE; | |
281 | } | |
282 | ||
283 | const wxString& GetFile() const | |
284 | { | |
285 | return m_file; | |
286 | } | |
287 | ||
288 | private: | |
289 | wxString m_file; | |
290 | ||
291 | wxDECLARE_NO_COPY_CLASS(wxDirTraverserFindFirst); | |
292 | }; | |
293 | ||
294 | /* static */ | |
295 | wxString wxDir::FindFirst(const wxString& dirname, | |
296 | const wxString& filespec, | |
297 | int flags) | |
298 | { | |
299 | wxDir dir(dirname); | |
300 | if ( dir.IsOpened() ) | |
301 | { | |
302 | wxDirTraverserFindFirst traverser; | |
303 | ||
304 | dir.Traverse(traverser, filespec, flags | wxDIR_FILES); | |
305 | return traverser.GetFile(); | |
306 | } | |
307 | ||
308 | return wxEmptyString; | |
309 | } | |
310 | ||
311 | ||
312 | // ---------------------------------------------------------------------------- | |
313 | // wxDir::GetTotalSize() | |
314 | // ---------------------------------------------------------------------------- | |
315 | ||
316 | #if wxUSE_LONGLONG | |
317 | ||
318 | class wxDirTraverserSumSize : public wxDirTraverser | |
319 | { | |
320 | public: | |
321 | wxDirTraverserSumSize() { } | |
322 | ||
323 | virtual wxDirTraverseResult OnFile(const wxString& filename) | |
324 | { | |
325 | // wxFileName::GetSize won't use this class again as | |
326 | // we're passing it a file and not a directory; | |
327 | // thus we are sure to avoid an endless loop | |
328 | wxULongLong sz = wxFileName::GetSize(filename); | |
329 | ||
330 | if (sz == wxInvalidSize) | |
331 | { | |
332 | // if the GetSize() failed (this can happen because e.g. a | |
333 | // file is locked by another process), we can proceed but | |
334 | // we need to at least warn the user that the resulting | |
335 | // final size could be not reliable (if e.g. the locked | |
336 | // file is very big). | |
337 | m_skippedFiles.Add(filename); | |
338 | return wxDIR_CONTINUE; | |
339 | } | |
340 | ||
341 | m_sz += sz; | |
342 | return wxDIR_CONTINUE; | |
343 | } | |
344 | ||
345 | virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) | |
346 | { | |
347 | return wxDIR_CONTINUE; | |
348 | } | |
349 | ||
350 | wxULongLong GetTotalSize() const | |
351 | { return m_sz; } | |
352 | const wxArrayString& GetSkippedFiles() const | |
353 | { return m_skippedFiles; } | |
354 | ||
355 | protected: | |
356 | wxULongLong m_sz; | |
357 | wxArrayString m_skippedFiles; | |
358 | }; | |
359 | ||
360 | wxULongLong wxDir::GetTotalSize(const wxString &dirname, wxArrayString *filesSkipped) | |
361 | { | |
362 | if (!wxDirExists(dirname)) | |
363 | return wxInvalidSize; | |
364 | ||
365 | // to get the size of this directory and its contents we need | |
366 | // to recursively walk it... | |
367 | wxDir dir(dirname); | |
368 | if ( !dir.IsOpened() ) | |
369 | return wxInvalidSize; | |
370 | ||
371 | wxDirTraverserSumSize traverser; | |
372 | if (dir.Traverse(traverser) == (size_t)-1 ) | |
373 | return wxInvalidSize; | |
374 | ||
375 | if (filesSkipped) | |
376 | *filesSkipped = traverser.GetSkippedFiles(); | |
377 | ||
378 | return traverser.GetTotalSize(); | |
379 | } | |
380 | ||
381 | #endif // wxUSE_LONGLONG | |
382 | ||
383 | // ---------------------------------------------------------------------------- | |
384 | // wxDir helpers | |
385 | // ---------------------------------------------------------------------------- | |
386 | ||
387 | /* static */ | |
388 | bool wxDir::Exists(const wxString& dir) | |
389 | { | |
390 | return wxFileName::DirExists(dir); | |
391 | } | |
392 | ||
393 | /* static */ | |
394 | bool wxDir::Make(const wxString &dir, int perm, int flags) | |
395 | { | |
396 | return wxFileName::Mkdir(dir, perm, flags); | |
397 | } | |
398 | ||
399 | /* static */ | |
400 | bool wxDir::Remove(const wxString &dir, int flags) | |
401 | { | |
402 | return wxFileName::Rmdir(dir, flags); | |
403 | } | |
404 |