Define QT_OPEN_LARGEFILE on Symbian + WinCE
[qt-netbsd.git] / src / corelib / io / qdiriterator.cpp
blob6247b00f781ab6ce325222506f68e81f4f824777
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 /*!
43 \since 4.3
44 \class QDirIterator
45 \brief The QDirIterator class provides an iterator for directory entrylists.
47 You can use QDirIterator to navigate entries of a directory one at a time.
48 It is similar to QDir::entryList() and QDir::entryInfoList(), but because
49 it lists entries one at a time instead of all at once, it scales better
50 and is more suitable for large directories. It also supports listing
51 directory contents recursively, and following symbolic links. Unlike
52 QDir::entryList(), QDirIterator does not support sorting.
54 The QDirIterator constructor takes a QDir or a directory as
55 argument. After construction, the iterator is located before the first
56 directory entry. Here's how to iterate over all the entries sequentially:
58 \snippet doc/src/snippets/code/src_corelib_io_qdiriterator.cpp 0
60 The next() function returns the path to the next directory entry and
61 advances the iterator. You can also call filePath() to get the current
62 file path without advancing the iterator. The fileName() function returns
63 only the name of the file, similar to how QDir::entryList() works. You can
64 also call fileInfo() to get a QFileInfo for the current entry.
66 Unlike Qt's container iterators, QDirIterator is uni-directional (i.e.,
67 you cannot iterate directories in reverse order) and does not allow random
68 access.
70 QDirIterator works with all supported file engines, and is implemented
71 using QAbstractFileEngineIterator.
73 \sa QDir, QDir::entryList(), QAbstractFileEngineIterator
76 /*! \enum QDirIterator::IteratorFlag
78 This enum describes flags that you can combine to configure the behavior
79 of QDirIterator.
81 \value NoIteratorFlags The default value, representing no flags. The
82 iterator will return entries for the assigned path.
84 \value Subdirectories List entries inside all subdirectories as well.
86 \value FollowSymlinks When combined with Subdirectories, this flag
87 enables iterating through all subdirectories of the assigned path,
88 following all symbolic links. Symbolic link loops (e.g., "link" => "." or
89 "link" => "..") are automatically detected and ignored.
92 #include "qdiriterator.h"
94 #include "qabstractfileengine.h"
96 #include <QtCore/qset.h>
97 #include <QtCore/qstack.h>
98 #include <QtCore/qvariant.h>
100 QT_BEGIN_NAMESPACE
102 class QDirIteratorPrivateIteratorStack : public QStack<QAbstractFileEngineIterator *>
104 public:
105 ~QDirIteratorPrivateIteratorStack();
108 QDirIteratorPrivateIteratorStack::~QDirIteratorPrivateIteratorStack()
110 qDeleteAll(*this);
114 class QDirIteratorPrivate
116 public:
117 QDirIteratorPrivate(const QString &path, const QStringList &nameFilters,
118 QDir::Filters filters, QDirIterator::IteratorFlags flags);
119 ~QDirIteratorPrivate();
121 void advance();
123 void pushDirectory(const QFileInfo &fileInfo);
124 void checkAndPushDirectory(const QFileInfo &);
125 bool matchesFilters(const QString &fileName, const QFileInfo &fi) const;
127 QScopedPointer<QAbstractFileEngine> engine;
129 const QString path;
130 const QStringList nameFilters;
131 const QDir::Filters filters;
132 const QDirIterator::IteratorFlags iteratorFlags;
134 #ifndef QT_NO_REGEXP
135 QVector<QRegExp> nameRegExps;
136 #endif
138 QDirIteratorPrivateIteratorStack fileEngineIterators;
139 QFileInfo currentFileInfo;
140 QFileInfo nextFileInfo;
142 // Loop protection
143 QSet<QString> visitedLinks;
145 QDirIterator *q;
149 \internal
151 QDirIteratorPrivate::QDirIteratorPrivate(const QString &path, const QStringList &nameFilters,
152 QDir::Filters filters, QDirIterator::IteratorFlags flags)
153 : engine(QAbstractFileEngine::create(path))
154 , path(path)
155 , nameFilters(nameFilters.contains(QLatin1String("*")) ? QStringList() : nameFilters)
156 , filters(QDir::NoFilter == filters ? QDir::AllEntries : filters)
157 , iteratorFlags(flags)
159 #ifndef QT_NO_REGEXP
160 nameRegExps.reserve(nameFilters.size());
161 for (int i = 0; i < nameFilters.size(); ++i)
162 nameRegExps.append(
163 QRegExp(nameFilters.at(i),
164 (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive,
165 QRegExp::Wildcard));
166 #endif
168 // Populate fields for hasNext() and next()
169 pushDirectory(QFileInfo(path));
170 advance();
174 \internal
176 QDirIteratorPrivate::~QDirIteratorPrivate()
181 \internal
183 void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo)
185 QString path = fileInfo.filePath();
187 #ifdef Q_OS_WIN
188 if (fileInfo.isSymLink())
189 path = fileInfo.canonicalFilePath();
190 #endif
192 if (iteratorFlags & QDirIterator::FollowSymlinks)
193 visitedLinks << fileInfo.canonicalFilePath();
195 if (engine) {
196 engine->setFileName(path);
197 QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters);
198 if (it) {
199 it->setPath(path);
200 fileEngineIterators << it;
201 } else {
202 // No iterator; no entry list.
208 \internal
210 void QDirIteratorPrivate::advance()
212 while (!fileEngineIterators.isEmpty()) {
214 // Find the next valid iterator that matches the filters.
215 while (fileEngineIterators.top()->hasNext()) {
216 QAbstractFileEngineIterator *it = fileEngineIterators.top();
217 it->next();
219 const QFileInfo info = it->currentFileInfo();
220 checkAndPushDirectory(it->currentFileInfo());
222 if (matchesFilters(it->currentFileName(), info)) {
223 currentFileInfo = nextFileInfo;
224 nextFileInfo = info;
226 //We found a matching entry.
227 return;
231 delete fileEngineIterators.pop();
234 currentFileInfo = nextFileInfo;
235 nextFileInfo = QFileInfo();
239 \internal
241 void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo)
243 // If we're doing flat iteration, we're done.
244 if (!(iteratorFlags & QDirIterator::Subdirectories))
245 return;
247 // Never follow non-directory entries
248 if (!fileInfo.isDir())
249 return;
251 // Follow symlinks only when asked
252 if (!(iteratorFlags & QDirIterator::FollowSymlinks) && fileInfo.isSymLink())
253 return;
255 // Never follow . and ..
256 QString fileName = fileInfo.fileName();
257 if (QLatin1String(".") == fileName || QLatin1String("..") == fileName)
258 return;
260 // No hidden directories unless requested
261 if (!(filters & QDir::AllDirs) && !(filters & QDir::Hidden) && fileInfo.isHidden())
262 return;
264 // Stop link loops
265 if (visitedLinks.contains(fileInfo.canonicalFilePath()))
266 return;
268 pushDirectory(fileInfo);
272 \internal
274 This convenience function implements the iterator's filtering logics and
275 applies then to the current directory entry.
277 It returns true if the current entry matches the filters (i.e., the
278 current entry will be returned as part of the directory iteration);
279 otherwise, false is returned.
281 bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInfo &fi) const
283 Q_ASSERT(!fileName.isEmpty());
285 // filter . and ..?
286 const int fileNameSize = fileName.size();
287 const bool dotOrDotDot = fileName[0] == QLatin1Char('.')
288 && ((fileNameSize == 1)
289 ||(fileNameSize == 2 && fileName[1] == QLatin1Char('.')));
290 if ((filters & QDir::NoDotAndDotDot) && dotOrDotDot)
291 return false;
293 // name filter
294 #ifndef QT_NO_REGEXP
295 // Pass all entries through name filters, except dirs if the AllDirs
296 if (!nameFilters.isEmpty() && !((filters & QDir::AllDirs) && fi.isDir())) {
297 bool matched = false;
298 for (QVector<QRegExp>::const_iterator iter = nameRegExps.constBegin(),
299 end = nameRegExps.constEnd();
300 iter != end; ++iter) {
302 if (iter->exactMatch(fileName)) {
303 matched = true;
304 break;
307 if (!matched)
308 return false;
310 #endif
312 // filter hidden
313 const bool includeHidden = (filters & QDir::Hidden);
314 if (!includeHidden && !dotOrDotDot && fi.isHidden())
315 return false;
317 // filter system files
318 const bool includeSystem = (filters & QDir::System);
319 if (!includeSystem && ((!fi.isFile() && !fi.isDir() && !fi.isSymLink())
320 || (!fi.exists() && fi.isSymLink())))
321 return false;
323 // skip directories
324 const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
325 if (skipDirs && fi.isDir()) {
326 if (!((includeHidden && !dotOrDotDot && fi.isHidden())
327 || (includeSystem && !fi.exists() && fi.isSymLink())))
328 return false;
331 // skip files
332 const bool skipFiles = !(filters & QDir::Files);
333 const bool skipSymlinks = (filters & QDir::NoSymLinks);
334 if ((skipFiles && (fi.isFile() || !fi.exists())) || (skipSymlinks && fi.isSymLink())) {
335 if (!((includeHidden && !dotOrDotDot && fi.isHidden())
336 || (includeSystem && !fi.exists() && fi.isSymLink())))
337 return false;
340 // filter permissions
341 const bool filterPermissions = ((filters & QDir::PermissionMask)
342 && (filters & QDir::PermissionMask) != QDir::PermissionMask);
343 const bool doWritable = !filterPermissions || (filters & QDir::Writable);
344 const bool doExecutable = !filterPermissions || (filters & QDir::Executable);
345 const bool doReadable = !filterPermissions || (filters & QDir::Readable);
346 if (filterPermissions
347 && ((doReadable && !fi.isReadable())
348 || (doWritable && !fi.isWritable())
349 || (doExecutable && !fi.isExecutable()))) {
350 return false;
353 return true;
357 Constructs a QDirIterator that can iterate over \a dir's entrylist, using
358 \a dir's name filters and regular filters. You can pass options via \a
359 flags to decide how the directory should be iterated.
361 By default, \a flags is NoIteratorFlags, which provides the same behavior
362 as in QDir::entryList().
364 The sorting in \a dir is ignored.
366 \note To list symlinks that point to non existing files, QDir::System must be
367 passed to the flags.
369 \sa hasNext(), next(), IteratorFlags
371 QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
372 : d(new QDirIteratorPrivate(dir.path(), dir.nameFilters(), dir.filter(), flags))
374 d->q = this;
378 Constructs a QDirIterator that can iterate over \a path, with no name
379 filtering and \a filters for entry filtering. You can pass options via \a
380 flags to decide how the directory should be iterated.
382 By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags,
383 which provides the same behavior as in QDir::entryList().
385 \note To list symlinks that point to non existing files, QDir::System must be
386 passed to the flags.
388 \warning This constructor expects \a flags to be left at its default value. Use
389 the constructors that do not take the \a filters argument instead.
391 \sa hasNext(), next(), IteratorFlags
393 QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
394 : d(new QDirIteratorPrivate(path, QStringList(), filters, flags))
396 d->q = this;
400 Constructs a QDirIterator that can iterate over \a path. You can pass
401 options via \a flags to decide how the directory should be iterated.
403 By default, \a flags is NoIteratorFlags, which provides the same behavior
404 as in QDir::entryList().
406 \note To list symlinks that point to non existing files, QDir::System must be
407 passed to the flags.
409 \sa hasNext(), next(), IteratorFlags
411 QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
412 : d(new QDirIteratorPrivate(path, QStringList(), QDir::NoFilter, flags))
414 d->q = this;
418 Constructs a QDirIterator that can iterate over \a path, using \a
419 nameFilters and \a filters. You can pass options via \a flags to decide
420 how the directory should be iterated.
422 By default, \a flags is NoIteratorFlags, which provides the same behavior
423 as QDir::entryList().
425 \note To list symlinks that point to non existing files, QDir::System must be
426 passed to the flags.
428 \warning This constructor expects \c flags to be left at its default value. Use the
429 constructors that do not take the \a filters argument instead.
431 \sa hasNext(), next(), IteratorFlags
433 QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters,
434 QDir::Filters filters, IteratorFlags flags)
435 : d(new QDirIteratorPrivate(path, nameFilters, filters, flags))
437 d->q = this;
441 Destroys the QDirIterator.
443 QDirIterator::~QDirIterator()
448 Advances the iterator to the next entry, and returns the file path of this
449 new entry. If hasNext() returns false, this function does nothing, and
450 returns a null QString.
452 You can call fileName() or filePath() to get the current entry file name
453 or path, or fileInfo() to get a QFileInfo for the current entry.
455 \sa hasNext(), fileName(), filePath(), fileInfo()
457 QString QDirIterator::next()
459 d->advance();
460 return filePath();
464 Returns true if there is at least one more entry in the directory;
465 otherwise, false is returned.
467 \sa next(), fileName(), filePath(), fileInfo()
469 bool QDirIterator::hasNext() const
471 return !d->fileEngineIterators.isEmpty();
475 Returns the file name for the current directory entry, without the path
476 prepended.
478 This function is convenient when iterating a single directory. When using
479 the QDirIterator::Subdirectories flag, you can use filePath() to get the
480 full path.
482 \sa filePath(), fileInfo()
484 QString QDirIterator::fileName() const
486 return d->currentFileInfo.fileName();
490 Returns the full file path for the current directory entry.
492 \sa fileInfo(), fileName()
494 QString QDirIterator::filePath() const
496 return d->currentFileInfo.filePath();
500 Returns a QFileInfo for the current directory entry.
502 \sa filePath(), fileName()
504 QFileInfo QDirIterator::fileInfo() const
506 return d->currentFileInfo;
510 Returns the base directory of the iterator.
512 QString QDirIterator::path() const
514 return d->path;
517 QT_END_NAMESPACE