Deprecate wxPathExists, make wxDirExists used everywhere, minor source cleaning.
[wxWidgets.git] / src / unix / dir.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: unix/dir.cpp
3 // Purpose: wxDir implementation for Unix/POSIX systems
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 08.12.99
7 // RCS-ID: $Id$
8 // Copyright: (c) 1999 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "dir.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/intl.h"
33 #include "wx/log.h"
34 #endif // PCH
35
36 #include "wx/dir.h"
37 #include "wx/filefn.h" // for wxMatchWild
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42
43 #include <dirent.h>
44
45 // ----------------------------------------------------------------------------
46 // macros
47 // ----------------------------------------------------------------------------
48
49 #define M_DIR ((wxDirData *)m_data)
50
51 // ----------------------------------------------------------------------------
52 // private classes
53 // ----------------------------------------------------------------------------
54
55 // this class stores everything we need to enumerate the files
56 class wxDirData
57 {
58 public:
59 wxDirData(const wxString& dirname);
60 ~wxDirData();
61
62 bool IsOk() const { return m_dir != NULL; }
63
64 void SetFileSpec(const wxString& filespec) { m_filespec = filespec; }
65 void SetFlags(int flags) { m_flags = flags; }
66
67 void Rewind() { rewinddir(m_dir); }
68 bool Read(wxString *filename);
69
70 const wxString& GetName() const { return m_dirname; }
71
72 private:
73 DIR *m_dir;
74
75 wxString m_dirname;
76 wxString m_filespec;
77
78 int m_flags;
79 };
80
81 // ============================================================================
82 // implementation
83 // ============================================================================
84
85 // ----------------------------------------------------------------------------
86 // wxDirData
87 // ----------------------------------------------------------------------------
88
89 #if !defined( __VMS__ ) || ( __VMS_VER >= 70000000 )
90
91 wxDirData::wxDirData(const wxString& dirname)
92 : m_dirname(dirname)
93 {
94 m_dir = NULL;
95
96 // throw away the trailing slashes
97 size_t n = m_dirname.length();
98 wxCHECK_RET( n, _T("empty dir name in wxDir") );
99
100 while ( n > 0 && m_dirname[--n] == '/' )
101 ;
102
103 m_dirname.Truncate(n + 1);
104
105 // do open the dir
106 m_dir = opendir(m_dirname.fn_str());
107 }
108
109 wxDirData::~wxDirData()
110 {
111 if ( m_dir )
112 {
113 if ( closedir(m_dir) != 0 )
114 {
115 wxLogLastError(_T("closedir"));
116 }
117 }
118 }
119
120 bool wxDirData::Read(wxString *filename)
121 {
122 dirent *de = (dirent *)NULL; // just to silence compiler warnings
123 bool matches = false;
124
125 // speed up string concatenation in the loop a bit
126 wxString path = m_dirname;
127 path += _T('/');
128 path.reserve(path.length() + 255);
129
130 wxString de_d_name;
131
132 while ( !matches )
133 {
134 de = readdir(m_dir);
135 if ( !de )
136 return false;
137
138 #if wxUSE_UNICODE
139 de_d_name = wxConvFileName->cMB2WC( de->d_name );
140 #else
141 de_d_name = de->d_name;
142 #endif
143
144 // don't return "." and ".." unless asked for
145 if ( de->d_name[0] == '.' &&
146 ((de->d_name[1] == '.' && de->d_name[2] == '\0') ||
147 (de->d_name[1] == '\0')) )
148 {
149 if ( !(m_flags & wxDIR_DOTDOT) )
150 continue;
151
152 // we found a valid match
153 break;
154 }
155
156 // check the type now
157 if ( !(m_flags & wxDIR_FILES) && !wxDir::Exists(path + de_d_name) )
158 {
159 // it's a file, but we don't want them
160 continue;
161 }
162 else if ( !(m_flags & wxDIR_DIRS) && wxDir::Exists(path + de_d_name) )
163 {
164 // it's a dir, and we don't want it
165 continue;
166 }
167
168 // finally, check the name
169 if ( m_filespec.empty() )
170 {
171 matches = m_flags & wxDIR_HIDDEN ? true : de->d_name[0] != '.';
172 }
173 else
174 {
175 // test against the pattern
176 matches = wxMatchWild(m_filespec, de_d_name,
177 !(m_flags & wxDIR_HIDDEN));
178 }
179 }
180
181 *filename = de_d_name;
182
183 return true;
184 }
185
186 #else // old VMS (TODO)
187
188 wxDirData::wxDirData(const wxString& WXUNUSED(dirname))
189 {
190 wxFAIL_MSG(_T("not implemented"));
191 }
192
193 wxDirData::~wxDirData()
194 {
195 }
196
197 bool wxDirData::Read(wxString * WXUNUSED(filename))
198 {
199 return false;
200 }
201
202 #endif // not or new VMS/old VMS
203
204 // ----------------------------------------------------------------------------
205 // wxDir helpers
206 // ----------------------------------------------------------------------------
207
208 /* static */
209 bool wxDir::Exists(const wxString& dir)
210 {
211 return wxDirExists(dir);
212 }
213
214 // ----------------------------------------------------------------------------
215 // wxDir construction/destruction
216 // ----------------------------------------------------------------------------
217
218 wxDir::wxDir(const wxString& dirname)
219 {
220 m_data = NULL;
221
222 (void)Open(dirname);
223 }
224
225 bool wxDir::Open(const wxString& dirname)
226 {
227 delete M_DIR;
228 m_data = new wxDirData(dirname);
229
230 if ( !M_DIR->IsOk() )
231 {
232 wxLogSysError(_("Can not enumerate files in directory '%s'"),
233 dirname.c_str());
234
235 delete M_DIR;
236 m_data = NULL;
237
238 return false;
239 }
240
241 return true;
242 }
243
244 bool wxDir::IsOpened() const
245 {
246 return m_data != NULL;
247 }
248
249 wxString wxDir::GetName() const
250 {
251 wxString name;
252 if ( m_data )
253 {
254 name = M_DIR->GetName();
255 if ( !name.empty() && (name.Last() == _T('/')) )
256 {
257 // chop off the last (back)slash
258 name.Truncate(name.length() - 1);
259 }
260 }
261
262 return name;
263 }
264
265 wxDir::~wxDir()
266 {
267 delete M_DIR;
268 }
269
270 // ----------------------------------------------------------------------------
271 // wxDir enumerating
272 // ----------------------------------------------------------------------------
273
274 bool wxDir::GetFirst(wxString *filename,
275 const wxString& filespec,
276 int flags) const
277 {
278 wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
279
280 M_DIR->Rewind();
281
282 M_DIR->SetFileSpec(filespec);
283 M_DIR->SetFlags(flags);
284
285 return GetNext(filename);
286 }
287
288 bool wxDir::GetNext(wxString *filename) const
289 {
290 wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
291
292 wxCHECK_MSG( filename, false, _T("bad pointer in wxDir::GetNext()") );
293
294 return M_DIR->Read(filename);
295 }
296
297 bool wxDir::HasSubDirs(const wxString& spec)
298 {
299 wxCHECK_MSG( IsOpened(), false, _T("must wxDir::Open() first") );
300
301 if ( spec.empty() )
302 {
303 // faster check for presence of any subdirectory: normally each subdir
304 // has a hard link to the parent directory and so, knowing that there
305 // are at least "." and "..", we have a subdirectory if and only if
306 // links number is > 2 - this is just a guess but it works fairly well
307 // in practice
308 //
309 // note that we may guess wrongly in one direction only: i.e. we may
310 // return true when there are no subdirectories but this is ok as the
311 // caller will learn it soon enough when it calls GetFirst(wxDIR)
312 // anyhow
313 wxStructStat stBuf;
314 if ( wxStat(M_DIR->GetName().c_str(), &stBuf) == 0 )
315 {
316 switch ( stBuf.st_nlink )
317 {
318 case 2:
319 // just "." and ".."
320 return false;
321
322 case 0:
323 case 1:
324 // weird filesystem, don't try to guess for it, use dumb
325 // method below
326 break;
327
328 default:
329 // assume we have subdirs - may turn out to be wrong if we
330 // have other hard links to this directory but it's not
331 // that bad as explained above
332 return true;
333 }
334 }
335 }
336
337 // just try to find first directory
338 wxString s;
339 return GetFirst(&s, spec, wxDIR_DIRS | wxDIR_HIDDEN);
340 }
341