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