]> git.saurik.com Git - wxWidgets.git/blame - src/unix/dir.cpp
scrolling to selection
[wxWidgets.git] / src / unix / dir.cpp
CommitLineData
1944c6bd
VZ
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>
6aa89a22 9// Licence: wxWindows licence
1944c6bd
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
1944c6bd
VZ
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>
1357a7dd
VZ
40#include <sys/stat.h>
41#include <unistd.h>
1944c6bd
VZ
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
56class wxDirData
57{
58public:
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
35332784
VZ
70 const wxString& GetName() const { return m_dirname; }
71
1944c6bd
VZ
72private:
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
91wxDirData::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
109wxDirData::~wxDirData()
110{
111 if ( m_dir )
112 {
113 if ( closedir(m_dir) != 0 )
114 {
115 wxLogLastError(_T("closedir"));
116 }
117 }
118}
119
120bool wxDirData::Read(wxString *filename)
121{
b0d36402 122 dirent *de = (dirent *)NULL; // just to silence compiler warnings
1944c6bd
VZ
123 bool matches = FALSE;
124
b0d36402
VZ
125 // speed up string concatenation in the loop a bit
126 wxString path = m_dirname;
127 path += _T('/');
128 path.reserve(path.length() + 255);
e6ccaf1a
RR
129
130 wxString de_d_name;
b0d36402 131
1944c6bd
VZ
132 while ( !matches )
133 {
134 de = readdir(m_dir);
135 if ( !de )
136 return FALSE;
e6ccaf1a
RR
137
138#if wxUSE_UNICODE
139 de_d_name = wxConvLibc.cMB2WC( de->d_name );
140#else
141 de_d_name = de->d_name;
142#endif
1944c6bd
VZ
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;
b0d36402
VZ
151
152 // we found a valid match
153 break;
1944c6bd
VZ
154 }
155
156 // check the type now
e6ccaf1a 157 if ( !(m_flags & wxDIR_FILES) && !wxDir::Exists(path + de_d_name) )
1944c6bd
VZ
158 {
159 // it's a file, but we don't want them
160 continue;
161 }
e6ccaf1a 162 else if ( !(m_flags & wxDIR_DIRS) && wxDir::Exists(path + de_d_name) )
1944c6bd
VZ
163 {
164 // it's a dir, and we don't want it
165 continue;
166 }
167
168 // finally, check the name
b0d36402 169 if ( m_filespec.empty() )
1944c6bd
VZ
170 {
171 matches = m_flags & wxDIR_HIDDEN ? TRUE : de->d_name[0] != '.';
172 }
173 else
174 {
175 // test against the pattern
e6ccaf1a 176 matches = wxMatchWild(m_filespec, de_d_name,
1944c6bd
VZ
177 !(m_flags & wxDIR_HIDDEN));
178 }
179 }
180
e6ccaf1a 181 *filename = de_d_name;
1944c6bd
VZ
182
183 return TRUE;
184}
185
186#else // old VMS (TODO)
187
188wxDirData::wxDirData(const wxString& WXUNUSED(dirname))
189{
190 wxFAIL_MSG(_T("not implemented"));
191}
192
193wxDirData::~wxDirData()
194{
195}
196
197bool 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 */
209bool wxDir::Exists(const wxString& dir)
210{
211 return wxPathExists(dir);
212}
213
214// ----------------------------------------------------------------------------
215// wxDir construction/destruction
216// ----------------------------------------------------------------------------
217
218wxDir::wxDir(const wxString& dirname)
219{
220 m_data = NULL;
221
222 (void)Open(dirname);
223}
224
225bool 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
244bool wxDir::IsOpened() const
245{
246 return m_data != NULL;
247}
248
35332784
VZ
249wxString 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
1944c6bd
VZ
265wxDir::~wxDir()
266{
267 delete M_DIR;
268}
269
270// ----------------------------------------------------------------------------
271// wxDir enumerating
272// ----------------------------------------------------------------------------
273
274bool 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
288bool 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}
1357a7dd
VZ
296
297bool 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;
92980e90 314 if ( wxStat(M_DIR->GetName().c_str(), &stBuf) == 0 )
1357a7dd
VZ
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