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