|
1 /****************************************************************************** |
|
2 * |
|
3 * |
|
4 * |
|
5 * Copyright (C) 1997-2001 by Dimitri van Heesch. |
|
6 * |
|
7 * Permission to use, copy, modify, and distribute this software and its |
|
8 * documentation under the terms of the GNU General Public License is hereby |
|
9 * granted. No representations are made about the suitability of this software |
|
10 * for any purpose. It is provided "as is" without express or implied warranty. |
|
11 * See the GNU General Public License for more details. |
|
12 * |
|
13 * Documents produced by Doxygen are derivative works derived from the |
|
14 * input used in their production; they are not affected by this license. |
|
15 * |
|
16 * Based on qdir_unix.cpp |
|
17 * |
|
18 * Copyright (C) 1992-2000 Trolltech AS. |
|
19 */ |
|
20 |
|
21 |
|
22 #include "qglobal.h" |
|
23 |
|
24 #include "qdir.h" |
|
25 #ifndef QT_NO_DIR |
|
26 |
|
27 |
|
28 #include "qfileinfo.h" |
|
29 #include "qfiledefs_p.h" |
|
30 #include "qregexp.h" |
|
31 #include "qstringlist.h" |
|
32 #include <stdlib.h> |
|
33 #include <ctype.h> |
|
34 #if defined(_OS_WIN32_) |
|
35 #if defined(_CC_BOOL_DEF_) |
|
36 #undef bool |
|
37 #include <windows.h> |
|
38 #define bool int |
|
39 #else |
|
40 #include <windows.h> |
|
41 #endif |
|
42 #endif |
|
43 #if defined(_OS_OS2EMX_) |
|
44 extern Q_UINT32 DosQueryCurrentDisk(Q_UINT32*,Q_UINT32*); |
|
45 #define NO_ERROR 0 |
|
46 #endif |
|
47 |
|
48 extern QStringList qt_makeFilterList( const QString &filter ); |
|
49 |
|
50 extern int qt_cmp_si_sortSpec; |
|
51 |
|
52 #if defined(Q_C_CALLBACKS) |
|
53 extern "C" { |
|
54 #endif |
|
55 |
|
56 extern int qt_cmp_si( const void *, const void * ); |
|
57 |
|
58 #if defined(Q_C_CALLBACKS) |
|
59 } |
|
60 #endif |
|
61 |
|
62 |
|
63 void QDir::slashify( QString& n ) |
|
64 { |
|
65 for ( int i=0; i<(int)n.length(); i++ ) |
|
66 { |
|
67 if ( n[i] == '\\' ) |
|
68 n[i] = '/'; |
|
69 } |
|
70 } |
|
71 |
|
72 QString QDir::homeDirPath() |
|
73 { |
|
74 QString d; |
|
75 d = QFile::decodeName(getenv("HOME")); |
|
76 slashify( d ); |
|
77 if ( d.isNull() ) |
|
78 d = rootDirPath(); |
|
79 return d; |
|
80 } |
|
81 |
|
82 QString QDir::canonicalPath() const |
|
83 { |
|
84 QString r; |
|
85 |
|
86 char cur[PATH_MAX]; |
|
87 char tmp[PATH_MAX]; |
|
88 GETCWD( cur, PATH_MAX ); |
|
89 if ( CHDIR(QFile::encodeName(dPath)) >= 0 ) { |
|
90 GETCWD( tmp, PATH_MAX ); |
|
91 r = QFile::decodeName(tmp); |
|
92 } |
|
93 CHDIR( cur ); |
|
94 |
|
95 slashify( r ); |
|
96 return r; |
|
97 } |
|
98 |
|
99 bool QDir::mkdir( const QString &dirName, bool acceptAbsPath ) const |
|
100 { |
|
101 #if defined(__CYGWIN32_) |
|
102 return MKDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)), 0777 ) |
|
103 == 0; |
|
104 #else |
|
105 return MKDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)) ) == 0; |
|
106 |
|
107 #endif |
|
108 } |
|
109 |
|
110 bool QDir::rmdir( const QString &dirName, bool acceptAbsPath ) const |
|
111 { |
|
112 return RMDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)) ) == 0; |
|
113 } |
|
114 |
|
115 bool QDir::isReadable() const |
|
116 { |
|
117 return ACCESS( QFile::encodeName(dPath), R_OK ) == 0; |
|
118 } |
|
119 |
|
120 bool QDir::isRoot() const |
|
121 { |
|
122 return dPath == QString::fromLatin1("/"); |
|
123 } |
|
124 |
|
125 bool QDir::rename( const QString &name, const QString &newName, |
|
126 bool acceptAbsPaths ) |
|
127 { |
|
128 if ( name.isEmpty() || newName.isEmpty() ) { |
|
129 #if defined(CHECK_NULL) |
|
130 qWarning( "QDir::rename: Empty or null file name(s)" ); |
|
131 #endif |
|
132 return FALSE; |
|
133 } |
|
134 QString fn1 = filePath( name, acceptAbsPaths ); |
|
135 QString fn2 = filePath( newName, acceptAbsPaths ); |
|
136 return ::rename( QFile::encodeName(fn1), |
|
137 QFile::encodeName(fn2) ) == 0; |
|
138 } |
|
139 |
|
140 bool QDir::setCurrent( const QString &path ) |
|
141 { |
|
142 int r; |
|
143 r = CHDIR( QFile::encodeName(path) ); |
|
144 return r >= 0; |
|
145 } |
|
146 |
|
147 QString QDir::currentDirPath() |
|
148 { |
|
149 QString result; |
|
150 |
|
151 STATBUF st; |
|
152 if ( STAT( ".", &st ) == 0 ) { |
|
153 char currentName[PATH_MAX]; |
|
154 if ( GETCWD( currentName, PATH_MAX ) != 0 ) |
|
155 result = QFile::decodeName(currentName); |
|
156 #if defined(DEBUG) |
|
157 if ( result.isNull() ) |
|
158 qWarning( "QDir::currentDirPath: getcwd() failed" ); |
|
159 #endif |
|
160 } else { |
|
161 #if defined(DEBUG) |
|
162 qWarning( "QDir::currentDirPath: stat(\".\") failed" ); |
|
163 #endif |
|
164 } |
|
165 slashify( result ); |
|
166 return result; |
|
167 } |
|
168 |
|
169 QString QDir::rootDirPath() |
|
170 { |
|
171 QString d = QString::fromLatin1( "/" ); |
|
172 return d; |
|
173 } |
|
174 |
|
175 bool QDir::isRelativePath( const QString &path ) |
|
176 { |
|
177 int len = path.length(); |
|
178 if ( len == 0 ) |
|
179 return TRUE; |
|
180 int i = 0; |
|
181 if ( isalpha(path[0]) && path[1] == ':' ) // drive, e.g. a: |
|
182 i = 2; |
|
183 return path[i] != '/' && path[i] != '\\'; |
|
184 } |
|
185 |
|
186 #undef IS_SUBDIR |
|
187 #undef IS_RDONLY |
|
188 #undef IS_ARCH |
|
189 #undef IS_HIDDEN |
|
190 #undef IS_SYSTEM |
|
191 #undef FF_GETFIRST |
|
192 #undef FF_GETNEXT |
|
193 #undef FF_ERROR |
|
194 |
|
195 #if defined(_OS_WIN32_) |
|
196 #define IS_SUBDIR FILE_ATTRIBUTE_DIRECTORY |
|
197 #define IS_RDONLY FILE_ATTRIBUTE_READONLY |
|
198 #define IS_ARCH FILE_ATTRIBUTE_ARCHIVE |
|
199 #define IS_HIDDEN FILE_ATTRIBUTE_HIDDEN |
|
200 #define IS_SYSTEM FILE_ATTRIBUTE_SYSTEM |
|
201 #define FF_GETFIRST FindFirstFile |
|
202 #define FF_GETNEXT FindNextFile |
|
203 #define FF_ERROR INVALID_HANDLE_VALUE |
|
204 #else |
|
205 #define IS_SUBDIR _A_SUBDIR |
|
206 #define IS_RDONLY _A_RDONLY |
|
207 #define IS_ARCH _A_ARCH |
|
208 #define IS_HIDDEN _A_HIDDEN |
|
209 #define IS_SYSTEM _A_SYSTEM |
|
210 #define FF_GETFIRST _findfirst |
|
211 #define FF_GETNEXT _findnext |
|
212 #define FF_ERROR -1 |
|
213 #endif |
|
214 |
|
215 |
|
216 bool QDir::readDirEntries( const QString &nameFilter, |
|
217 int filterSpec, int sortSpec ) |
|
218 { |
|
219 int i; |
|
220 if ( !fList ) { |
|
221 fList = new QStringList; |
|
222 CHECK_PTR( fList ); |
|
223 fiList = new QFileInfoList; |
|
224 CHECK_PTR( fiList ); |
|
225 fiList->setAutoDelete( TRUE ); |
|
226 } else { |
|
227 fList->clear(); |
|
228 fiList->clear(); |
|
229 } |
|
230 |
|
231 QStringList filters = qt_makeFilterList( nameFilter ); |
|
232 |
|
233 bool doDirs = (filterSpec & Dirs) != 0; |
|
234 bool doFiles = (filterSpec & Files) != 0; |
|
235 bool noSymLinks = (filterSpec & NoSymLinks) != 0; |
|
236 bool doReadable = (filterSpec & Readable) != 0; |
|
237 bool doWritable = (filterSpec & Writable) != 0; |
|
238 bool doExecable = (filterSpec & Executable) != 0; |
|
239 bool doHidden = (filterSpec & Hidden) != 0; |
|
240 // show hidden files if the user asks explicitly for e.g. .* |
|
241 if ( !doHidden && !nameFilter.isEmpty() && nameFilter[0] == '.' ) |
|
242 doHidden = TRUE; |
|
243 bool doModified = (filterSpec & Modified) != 0; |
|
244 bool doSystem = (filterSpec & System) != 0; |
|
245 |
|
246 QRegExp wc( nameFilter, FALSE, TRUE ); // wild card, case insensitive |
|
247 bool first = TRUE; |
|
248 QString p = dPath.copy(); |
|
249 int plen = p.length(); |
|
250 #if defined(_OS_WIN32_) |
|
251 HANDLE ff; |
|
252 WIN32_FIND_DATA finfo; |
|
253 #else |
|
254 long ff; |
|
255 _finddata_t finfo; |
|
256 #endif |
|
257 QFileInfo fi; |
|
258 if ( plen == 0 ) |
|
259 { |
|
260 #if defined(CHECK_NULL) |
|
261 warning( "QDir::readDirEntries: No directory name specified" ); |
|
262 #endif |
|
263 return FALSE; |
|
264 } |
|
265 if ( p.at(plen-1) != '/' && p.at(plen-1) != '\\' ) |
|
266 p += '/'; |
|
267 p += "*.*"; |
|
268 |
|
269 ff = FF_GETFIRST( p.data(), &finfo ); |
|
270 if ( ff == FF_ERROR ) |
|
271 { |
|
272 #if defined(DEBUG) |
|
273 warning( "QDir::readDirEntries: Cannot read the directory: %s", |
|
274 (const char *)dPath ); |
|
275 #endif |
|
276 return FALSE; |
|
277 } |
|
278 |
|
279 while ( TRUE ) |
|
280 { |
|
281 if ( first ) |
|
282 first = FALSE; |
|
283 else |
|
284 { |
|
285 #if defined(_OS_WIN32_) |
|
286 if ( !FF_GETNEXT(ff,&finfo) ) |
|
287 break; |
|
288 #else |
|
289 if ( FF_GETNEXT(ff,&finfo) == -1 ) |
|
290 break; |
|
291 #endif |
|
292 } |
|
293 #if defined(_OS_WIN32_) |
|
294 int attrib = finfo.dwFileAttributes; |
|
295 #else |
|
296 int attrib = finfo.attrib; |
|
297 #endif |
|
298 bool isDir = (attrib & IS_SUBDIR) != 0; |
|
299 bool isFile = !isDir; |
|
300 bool isSymLink = FALSE; |
|
301 bool isReadable = TRUE; |
|
302 bool isWritable = (attrib & IS_RDONLY) == 0; |
|
303 bool isExecable = FALSE; |
|
304 bool isModified = (attrib & IS_ARCH) != 0; |
|
305 bool isHidden = (attrib & IS_HIDDEN) != 0; |
|
306 bool isSystem = (attrib & IS_SYSTEM) != 0; |
|
307 |
|
308 #if defined(_OS_WIN32_) |
|
309 const char *fname = finfo.cFileName; |
|
310 #else |
|
311 const char *fname = finfo.name; |
|
312 #endif |
|
313 if ( wc.match(fname) == -1 && !(allDirs && isDir) ) |
|
314 continue; |
|
315 |
|
316 QString name = fname; |
|
317 if ( doExecable ) |
|
318 { |
|
319 QString ext = name.right(4).lower(); |
|
320 if ( ext == ".exe" || ext == ".com" || ext == ".bat" || |
|
321 ext == ".pif" || ext == ".cmd" ) |
|
322 isExecable = TRUE; |
|
323 } |
|
324 |
|
325 if ( (doDirs && isDir) || (doFiles && isFile) ) |
|
326 { |
|
327 if ( noSymLinks && isSymLink ) |
|
328 continue; |
|
329 if ( (filterSpec & RWEMask) != 0 ) |
|
330 if ( (doReadable && !isReadable) || |
|
331 (doWritable && !isWritable) || |
|
332 (doExecable && !isExecable) ) |
|
333 continue; |
|
334 if ( doModified && !isModified ) |
|
335 continue; |
|
336 if ( !doHidden && isHidden ) |
|
337 continue; |
|
338 if ( !doSystem && isSystem ) |
|
339 continue; |
|
340 fi.setFile( *this, name ); |
|
341 fiList->append( new QFileInfo( fi ) ); |
|
342 } |
|
343 } |
|
344 #if defined(_OS_WIN32_) |
|
345 FindClose( ff ); |
|
346 #else |
|
347 _findclose( ff ); |
|
348 #endif |
|
349 |
|
350 // Sort... |
|
351 QDirSortItem* si= new QDirSortItem[fiList->count()]; |
|
352 QFileInfo* itm; |
|
353 i=0; |
|
354 for (itm = fiList->first(); itm; itm = fiList->next()) |
|
355 si[i++].item = itm; |
|
356 qt_cmp_si_sortSpec = sortSpec; |
|
357 qsort( si, i, sizeof(si[0]), qt_cmp_si ); |
|
358 // put them back in the list |
|
359 fiList->setAutoDelete( FALSE ); |
|
360 fiList->clear(); |
|
361 int j; |
|
362 for ( j=0; j<i; j++ ) { |
|
363 fiList->append( si[j].item ); |
|
364 fList->append( si[j].item->fileName() ); |
|
365 } |
|
366 delete [] si; |
|
367 fiList->setAutoDelete( TRUE ); |
|
368 |
|
369 if ( filterSpec == (FilterSpec)filtS && sortSpec == (SortSpec)sortS && |
|
370 nameFilter == nameFilt ) |
|
371 dirty = FALSE; |
|
372 else |
|
373 dirty = TRUE; |
|
374 return TRUE; |
|
375 } |
|
376 |
|
377 const QFileInfoList * QDir::drives() |
|
378 { |
|
379 // at most one instance of QFileInfoList is leaked, and this variable |
|
380 // points to that list |
|
381 static QFileInfoList * knownMemoryLeak = 0; |
|
382 |
|
383 if ( !knownMemoryLeak ) { |
|
384 knownMemoryLeak = new QFileInfoList; |
|
385 |
|
386 #if defined(_OS_WIN32_) |
|
387 Q_UINT32 driveBits = (Q_UINT32) GetLogicalDrives() & 0x3ffffff; |
|
388 #elif defined(_OS_OS2EMX_) |
|
389 Q_UINT32 driveBits, cur; |
|
390 if (DosQueryCurrentDisk(&cur,&driveBits) != NO_ERROR) |
|
391 exit(1); |
|
392 driveBits &= 0x3ffffff; |
|
393 #endif |
|
394 char driveName[4]; |
|
395 qstrcpy( driveName, "a:/" ); |
|
396 while( driveBits ) { |
|
397 if ( driveBits & 1 ) |
|
398 knownMemoryLeak->append( new QFileInfo( driveName ) ); |
|
399 driveName[0]++; |
|
400 driveBits = driveBits >> 1; |
|
401 } |
|
402 } |
|
403 |
|
404 return knownMemoryLeak; |
|
405 } |
|
406 #endif //QT_NO_DIR |