Imported Upstream version 1.8.15
[platform/upstream/doxygen.git] / qtools / qdir.cpp
1 /****************************************************************************
2 ** 
3 **
4 ** Implementation of QDir class
5 **
6 ** Created : 950427
7 **
8 ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
9 **
10 ** This file is part of the tools module of the Qt GUI Toolkit.
11 **
12 ** This file may be distributed under the terms of the Q Public License
13 ** as defined by Trolltech AS of Norway and appearing in the file
14 ** LICENSE.QPL included in the packaging of this file.
15 **
16 ** This file may be distributed and/or modified under the terms of the
17 ** GNU General Public License version 2 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.GPL included in the
19 ** packaging of this file.
20 **
21 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22 ** licenses may use this file in accordance with the Qt Commercial License
23 ** Agreement provided with the Software.
24 **
25 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27 **
28 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29 **   information about Qt Commercial License Agreements.
30 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
31 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
32 **
33 ** Contact info@trolltech.com if any conditions of this licensing are
34 ** not clear to you.
35 **
36 **********************************************************************/
37
38 #include "qglobal.h"
39
40 #include "qdir.h"
41
42 #ifndef QT_NO_DIR
43 #include "qfileinfo.h"
44 #include "qfiledefs_p.h"
45 #include "qregexp.h"
46 #include "qstringlist.h"
47 #include <stdlib.h>
48 #include <ctype.h>
49
50 // NOT REVISED
51 /*!
52   \class QDir qdir.h
53   \brief Traverses directory structures and contents in a
54             platform-independent way.
55
56   \ingroup io
57
58   A QDir can point to a file using either a relative or an absolute file
59   path. Absolute file paths begin with the directory separator ('/') or a
60   drive specification (not applicable to UNIX).  Relative file names begin
61   with a directory name or a file name and specify a path relative to the
62   current directory.
63
64   An example of an absolute path is the string "/tmp/quartz", a relative
65   path might look like "src/fatlib". You can use the function isRelative()
66   to check if a QDir is using a relative or an absolute file path. You can
67   call the function convertToAbs() to convert a relative QDir to an
68   absolute one.
69
70   The directory "example" under the current directory is checked for existence
71   in the example below:
72
73   \code
74     QDir d( "example" );                        // "./example"
75     if ( !d.exists() )
76         qWarning( "Cannot find the example directory" );
77   \endcode
78
79   If you always use '/' as a directory separator, Qt will translate your
80   paths to conform to the underlying operating system.
81
82   cd() and cdUp() can be used to navigate the directory tree. Note that the
83   logical cd and cdUp operations are not performed if the new directory does
84   not exist.
85
86   Example:
87   \code
88     QDir d = QDir::root();                      // "/"
89     if ( !d.cd("tmp") ) {                       // "/tmp"
90         qWarning( "Cannot find the \"/tmp\" directory" );
91     } else {
92         QFile f( d.filePath("ex1.txt") );       // "/tmp/ex1.txt"
93         if ( !f.open(IO_ReadWrite) )
94             qWarning( "Cannot create the file %s", f.name() );
95     }
96   \endcode
97
98   To read the contents of a directory you can use the entryList() and
99   entryInfoList() functions.
100
101   Example:
102   \code
103     #include <stdio.h>
104     #include <qdir.h>
105
106     //
107     // This program scans the current directory and lists all files
108     // that are not symbolic links, sorted by size with the smallest files
109     // first.
110     //
111
112     int main( int argc, char **argv )
113     {
114         QDir d;
115         d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks );
116         d.setSorting( QDir::Size | QDir::Reversed );
117
118         const QFileInfoList *list = d.entryInfoList();
119         QFileInfoListIterator it( *list );      // create list iterator
120         QFileInfo *fi;                          // pointer for traversing
121
122         printf( "     BYTES FILENAME\n" );      // print header
123         while ( (fi=it.current()) ) {           // for each file...
124             printf( "%10li %s\n", fi->size(), fi->fileName().data() );
125             ++it;                               // goto next list element
126         }
127     }
128   \endcode
129 */
130
131
132 /*!
133   Constructs a QDir pointing to the current directory.
134   \sa currentDirPath()
135 */
136
137 QDir::QDir()
138 {
139     dPath = QString::fromLatin1(".");
140     init();
141 }
142
143 /*!
144   Constructs a QDir.
145
146   \arg \e path is the directory.
147   \arg \e nameFilter is the file name filter.
148   \arg \e sortSpec is the sort specification, which describes how to
149   sort the files in the directory.
150   \arg \e filterSpec is the filter specification, which describes how
151   to filter the files in the directory.
152
153   Most of these arguments (except \e path) have optional values.
154
155   Example:
156   \code
157     // lists all files in /tmp
158
159     QDir d( "/tmp" );
160     for ( int i=0; i<d.count(); i++ )
161         printf( "%s\n", d[i] );
162   \endcode
163
164   If \e path is "" or null, the directory is set to "." (the current
165   directory).  If \e nameFilter is "" or null, it is set to "*" (all
166   files).
167
168   No check is made to ensure that the directory exists.
169
170   \sa exists(), setPath(), setNameFilter(), setFilter(), setSorting()
171 */
172
173 QDir::QDir( const QString &path, const QString &nameFilter,
174             int sortSpec, int filterSpec )
175 {
176     init();
177     dPath = cleanDirPath( path );
178     if ( dPath.isEmpty() )
179         dPath = QString::fromLatin1(".");
180     nameFilt = nameFilter;
181     if ( nameFilt.isEmpty() )
182         nameFilt = QString::fromLatin1("*");
183     filtS = (FilterSpec)filterSpec;
184     sortS = (SortSpec)sortSpec;
185 }
186
187 /*!
188   Constructs a QDir that is a copy of the given directory.
189   \sa operator=()
190 */
191
192 QDir::QDir( const QDir &d )
193 {
194     dPath = d.dPath;
195     fList = 0;
196     fiList = 0;
197     nameFilt = d.nameFilt;
198     dirty = TRUE;
199     allDirs = d.allDirs;
200     filtS = d.filtS;
201     sortS = d.sortS;
202 }
203
204
205 void QDir::init()
206 {
207     fList = 0;
208     fiList = 0;
209     nameFilt = QString::fromLatin1("*");
210     dirty = TRUE;
211     allDirs = FALSE;
212     filtS = All;
213     sortS = SortSpec(Name | IgnoreCase);
214 }
215
216 /*!
217   Destructs the QDir and cleans up.
218 */
219
220 QDir::~QDir()
221 {
222     if ( fList )
223        delete fList;
224     if ( fiList )
225        delete fiList;
226 }
227
228
229 /*!
230   Sets the path of the directory. The path is cleaned of redundant ".", ".."
231   and multiple separators. No check is made to ensure that a directory
232   with this path exists.
233
234   The path can be either absolute or relative. Absolute paths begin with the
235   directory separator ('/') or a drive specification (not
236   applicable to UNIX).
237   Relative file names begin with a directory name or a file name and specify
238   a path relative to the current directory. An example of
239   an absolute path is the string "/tmp/quartz", a relative path might look like
240   "src/fatlib". You can use the function isRelative() to check if a QDir
241   is using a relative or an absolute file path. You can call the function
242   convertToAbs() to convert a relative QDir to an absolute one.
243
244   \sa path(), absPath(), exists(), cleanDirPath(), dirName(),
245       absFilePath(), isRelative(), convertToAbs()
246 */
247
248 void QDir::setPath( const QString &path )
249 {
250     dPath = cleanDirPath( path );
251     if ( dPath.isEmpty() )
252         dPath = QString::fromLatin1(".");
253     dirty = TRUE;
254 }
255
256 /*!
257   \fn  QString QDir::path() const
258   Returns the path, this may contain symbolic links, but never contains
259   redundant ".", ".." or multiple separators.
260
261   The returned path can be either absolute or relative (see setPath()).
262
263   \sa setPath(), absPath(), exists(), cleanDirPath(), dirName(),
264   absFilePath(), convertSeparators()
265 */
266
267 /*!
268   Returns the absolute (a path that starts with '/') path, which may
269   contain symbolic links, but never contains redundant ".", ".." or
270   multiple separators.
271
272   \sa setPath(), canonicalPath(), exists(),  cleanDirPath(), dirName(),
273   absFilePath()
274 */
275
276 QString QDir::absPath() const
277 {
278     if ( QDir::isRelativePath(dPath) ) {
279         QString tmp = currentDirPath();
280         if ( tmp.right(1) != QString::fromLatin1("/") )
281             tmp += '/';
282         tmp += dPath;
283         return cleanDirPath( tmp );
284     } else {
285         return cleanDirPath( dPath );
286     }
287 }
288
289 /*!
290   Returns the name of the directory, this is NOT the same as the path, e.g.
291   a directory with the name "mail", might have the path "/var/spool/mail".
292   If the directory has no name (e.g. the root directory) a null string is
293   returned.
294
295   No check is made to ensure that a directory with this name actually exists.
296
297   \sa path(), absPath(), absFilePath(), exists(), QString::isNull()
298 */
299
300 QString QDir::dirName() const
301 {
302     int pos = dPath.findRev( '/' );
303     if ( pos == -1  )
304         return dPath;
305     return dPath.right( dPath.length() - pos - 1 );
306 }
307
308 /*!
309   Returns the path name of a file in the directory. Does NOT check if
310   the file actually exists in the directory. If the QDir is relative
311   the returned path name will also be relative. Redundant multiple separators
312   or "." and ".." directories in \e fileName will not be removed (see
313   cleanDirPath()).
314
315   If \e acceptAbsPath is TRUE a \e fileName starting with a separator
316   ('/') will be returned without change.
317   If \e acceptAbsPath is FALSE an absolute path will be appended to
318   the directory path.
319
320   \sa absFilePath(), isRelative(), canonicalPath()
321 */
322
323 QString QDir::filePath( const QString &fileName,
324                         bool acceptAbsPath ) const
325 {
326     if ( acceptAbsPath && !isRelativePath(fileName) )
327         return QString(fileName);
328
329     QString tmp = dPath;
330     if ( tmp.isEmpty() || (tmp[(int)tmp.length()-1] != '/' && !!fileName &&
331                            fileName[0] != '/') )
332         tmp += '/';
333     tmp += fileName;
334     return tmp;
335 }
336
337 /*!
338   Returns the absolute path name of a file in the directory. Does NOT check if
339   the file actually exists in the directory. Redundant multiple separators
340   or "." and ".." directories in \e fileName will NOT be removed (see
341   cleanDirPath()).
342
343   If \e acceptAbsPath is TRUE a \e fileName starting with a separator
344   ('/') will be returned without change.
345   if \e acceptAbsPath is FALSE an absolute path will be appended to
346   the directory path.
347
348   \sa filePath()
349 */
350
351 QString QDir::absFilePath( const QString &fileName,
352                            bool acceptAbsPath ) const
353 {
354     if ( acceptAbsPath && !isRelativePath( fileName ) )
355         return fileName;
356
357     QString tmp = absPath();
358     if ( tmp.isEmpty() || (tmp[(int)tmp.length()-1] != '/' && !!fileName &&
359                            fileName[0] != '/') )
360         tmp += '/';
361     tmp += fileName;
362     return tmp;
363 }
364
365
366 /*!
367   Converts the '/' separators in \a pathName to system native
368   separators.  Returns the translated string.
369
370   On Windows, convertSeparators("c:/winnt/system32") returns
371   "c:\winnt\system32".
372
373   No conversion is done on UNIX.
374 */
375
376 QString QDir::convertSeparators( const QString &pathName )
377 {
378     QString n( pathName );
379 #if defined(_OS_FATFS_) || defined(_OS_OS2EMX_)
380     for ( int i=0; i<(int)n.length(); i++ ) {
381         if ( n[i] == '/' )
382             n[i] = '\\';
383     }
384 #endif
385     return n;
386 }
387
388
389 /*!
390   Changes directory by descending into the given directory. Returns
391   TRUE if the new directory exists and is readable. Note that the logical
392   cd operation is NOT performed if the new directory does not exist.
393
394   If \e acceptAbsPath is TRUE a path starting with a separator ('/')
395   will cd to the absolute directory, if \e acceptAbsPath is FALSE
396   any number of separators at the beginning of \e dirName will be removed.
397
398   Example:
399   \code
400   QDir d = QDir::home();  // now points to home directory
401   if ( !d.cd("c++") ) {   // now points to "c++" under home directory if OK
402       QFileInfo fi( d, "c++" );
403       if ( fi.exists() ) {
404           if ( fi.isDir() )
405               qWarning( "Cannot cd into \"%s\".", (char*)d.absFilePath("c++") );
406           else
407               qWarning( "Cannot create directory \"%s\"\n"
408                        "A file named \"c++\" already exists in \"%s\"",
409                        (const char *)d.absFilePath("c++"),
410                        (const char *)d.path() );
411           return;
412       } else {
413           qWarning( "Creating directory \"%s\"",
414                    (const char *) d.absFilePath("c++") );
415           if ( !d.mkdir( "c++" ) ) {
416               qWarning("Could not create directory \"%s\"",
417                       (const char *)d.absFilePath("c++") );
418               return;
419           }
420       }
421   }
422   \endcode
423
424   Calling cd( ".." ) is equivalent to calling cdUp().
425
426   \sa cdUp(), isReadable(), exists(), path()
427 */
428
429 bool QDir::cd( const QString &dirName, bool acceptAbsPath )
430 {
431     if ( dirName.isEmpty() || dirName==QString::fromLatin1(".") )
432         return TRUE;
433     QString old = dPath;
434     if ( acceptAbsPath && !isRelativePath(dirName) ) {
435         dPath = cleanDirPath( dirName );
436     } else {
437         if ( !isRoot() )
438             dPath += '/';
439         dPath += dirName;
440         if ( dirName.find('/') >= 0
441                 || old == QString::fromLatin1(".")
442                 || dirName == QString::fromLatin1("..") )
443             dPath = cleanDirPath( dPath );
444     }
445     if ( !exists() ) {
446         dPath = old;                    // regret
447         return FALSE;
448     }
449     dirty = TRUE;
450     return TRUE;
451 }
452
453 /*!
454   Changes directory by moving one directory up the path followed to arrive
455   at the current directory.
456
457   Returns TRUE if the new directory exists and is readable. Note that the
458   logical cdUp() operation is not performed if the new directory does not
459   exist.
460
461   \sa cd(), isReadable(), exists(), path()
462 */
463
464 bool QDir::cdUp()
465 {
466     return cd( QString::fromLatin1("..") );
467 }
468
469 /*!
470   \fn QString QDir::nameFilter() const
471   Returns the string set by setNameFilter()
472 */
473
474 /*!
475   Sets the name filter used by entryList() and entryInfoList().
476
477   The name filter is a wildcarding filter that understands "*" and "?"
478   wildcards, You may specify several filter entries separated by a " " or a ";". If
479   you want entryList() and entryInfoList() to list all files ending with
480   ".cpp" and all files ending with ".h", you simply call
481   dir.setNameFilter("*.cpp *.h") or dir.setNameFilter("*.cpp;*.h")
482
483   \sa nameFilter(), setFilter()
484 */
485
486 void QDir::setNameFilter( const QString &nameFilter )
487 {
488     nameFilt = nameFilter;
489     if ( nameFilt.isEmpty() )
490         nameFilt = QString::fromLatin1("*");
491     dirty = TRUE;
492 }
493
494 /*!
495   \fn QDir::FilterSpec QDir::filter() const
496   Returns the value set by setFilter()
497 */
498
499 /*! \enum QDir::FilterSpec
500
501   This enum describes how QDir is to select what entries in a
502   directory to return.  The filter value is specified by or-ing
503   together values from the following list: <ul>
504
505   <li> \c Dirs - List directories only
506   <li> \c Files - List files only
507
508   <li> \c  Drives - List disk drives (does nothing under unix)
509   <li> \c  NoSymLinks - Do not list symbolic links (where they exist)
510   <li> \c  Readable - List files for which the application has read access.
511   <li> \c  Writable - List files for which the application has write access.
512   <li> \c  Executable - List files for which the application has execute access
513   <li> \c  Modified - Only list files that have been modified (does nothing
514   under unix)
515   <li> \c  Hidden - List hidden files (on unix, files starting with a .)
516   <li> \c  System - List system files (does nothing under unix)
517   </ul>
518
519   If you do not set any of \c Readable, \c Writable or \c Executable,
520   QDir will set all three of them.  This makes the default easy to
521   write and at the same time useful.
522
523   Examples: \c Readable|Writable means list all files for which the
524   application has read access, write access or both.  \c Dirs|Drives
525   means list drives, directories, all files that the application can
526   read, write or execute, and also symlinks to such files/directories.
527 */
528
529
530 /*!
531   Sets the filter used by entryList() and entryInfoList(). The filter is used
532   to specify the kind of files that should be returned by entryList() and
533   entryInfoList().
534
535   \sa filter(), setNameFilter()
536 */
537
538 void QDir::setFilter( int filterSpec )
539 {
540     if ( filtS == (FilterSpec) filterSpec )
541         return;
542     filtS = (FilterSpec) filterSpec;
543     dirty = TRUE;
544 }
545
546 /*!
547   \fn QDir::SortSpec QDir::sorting() const
548
549   Returns the value set by setSorting()
550
551   \sa setSorting()
552 */
553
554 /*! \enum QDir::SortSpec
555
556   This enum describes how QDir is to sort entries in a directory when
557   it returns a list of them.  The sort value is specified by or-ing
558   together values from the following list: <ul>
559
560   <li> \c Name - sort by name
561   <li> \c Time - sort by time (modification time)
562   <li> \c Size - sort by file size
563   <li> \c Unsorted - do not sort
564
565   <li> \c DirsFirst - put all directories first in the list
566   <li> \c Reversed - reverse the sort order
567   <li> \c IgnoreCase - sort case-insensitively
568
569   </ul>
570
571   You can only specify one of the first four.  If you specify both \c
572   DirsFirst and \c Reversed, directories are still put first but the
573   list is otherwise reversed.
574 */
575
576 // ### Unsorted+DirsFirst ? Unsorted+Reversed?
577
578 /*!
579   Sets the sorting order used by entryList() and entryInfoList().
580
581   The \e sortSpec is specified by or-ing values from the enum
582   SortSpec. The different values are:
583
584   One of these:
585   <dl compact>
586   <dt>Name<dd> Sort by name (alphabetical order).
587   <dt>Time<dd> Sort by time (most recent first).
588   <dt>Size<dd> Sort by size (largest first).
589   <dt>Unsorted<dd> Use the operating system order (UNIX does NOT sort
590   alphabetically).
591
592   ORed with zero or more of these:
593
594   <dt>DirsFirst<dd> Always put directory names first.
595   <dt>Reversed<dd> Reverse sort order.
596   <dt>IgnoreCase<dd> Ignore case when sorting by name.
597   </dl>
598 */
599
600 void QDir::setSorting( int sortSpec )
601 {
602     if ( sortS == (SortSpec) sortSpec )
603         return;
604     sortS = (SortSpec) sortSpec;
605     dirty = TRUE;
606 }
607
608 /*!
609   \fn bool QDir::matchAllDirs() const
610   Returns the value set by setMatchAllDirs()
611
612   \sa setMatchAllDirs()
613 */
614
615 /*!
616   If \e enable is TRUE, all directories will be listed (even if they do not
617   match the filter or the name filter), otherwise only matched directories
618   will be listed.
619
620   \bug Currently, directories that do not match the filter will not be
621   included (the name filter will be ignored as expected).
622
623   \sa matchAllDirs()
624 */
625
626 void QDir::setMatchAllDirs( bool enable )
627 {
628     if ( (bool)allDirs == enable )
629         return;
630     allDirs = enable;
631     dirty = TRUE;
632 }
633
634
635 /*!
636   Returns the number of files that was found.
637   Equivalent to entryList().count().
638   \sa operator[](), entryList()
639 */
640
641 uint QDir::count() const
642 {
643     return entryList().count();
644 }
645
646 /*!
647   Returns the file name at position \e index in the list of found file
648   names.
649   Equivalent to entryList().at(index).
650
651   Returns null if the \e index is out of range or if the entryList()
652   function failed.
653
654   \sa count(), entryList()
655 */
656
657 QString QDir::operator[]( int index ) const
658 {
659     entryList();
660     return fList && index >= 0 && index < (int)fList->count() ?
661         (*fList)[index] : QString::null;
662 }
663
664
665 /*!
666   This function is included to easy porting from Qt 1.x to Qt 2.0,
667   it is the same as entryList(), but encodes the filenames as 8-bit
668   strings using QFile::encodedName().
669
670   It is more efficient to use entryList().
671 */
672 QStrList QDir::encodedEntryList( int filterSpec, int sortSpec ) const
673 {
674     QStrList r;
675     QStringList l = entryList(filterSpec,sortSpec);
676     for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
677         r.append( QFile::encodeName(*it) );
678     }
679     return r;
680 }
681
682 /*!
683   This function is included to easy porting from Qt 1.x to Qt 2.0,
684   it is the same as entryList(), but encodes the filenames as 8-bit
685   strings using QFile::encodedName().
686
687   It is more efficient to use entryList().
688 */
689 QStrList QDir::encodedEntryList( const QString &nameFilter,
690                            int filterSpec,
691                            int sortSpec ) const
692 {
693     QStrList r;
694     QStringList l = entryList(nameFilter,filterSpec,sortSpec);
695     for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) {
696         r.append( QFile::encodeName(*it) );
697     }
698     return r;
699 }
700
701
702
703 /*!
704   Returns a list of the names of all files and directories in the directory
705   indicated by the setSorting(), setFilter() and setNameFilter()
706   specifications.
707
708   The filter and sorting specifications can be overridden using the
709   \e filterSpec and \e sortSpec arguments.
710
711   Returns an empty list if the directory is unreadable or does not exist.
712
713   \sa entryInfoList(), setNameFilter(), setSorting(), setFilter(),
714         encodedEntryList()
715 */
716
717 QStringList QDir::entryList( int filterSpec, int sortSpec ) const
718 {
719     if ( !dirty && filterSpec == (int)DefaultFilter &&
720                    sortSpec   == (int)DefaultSort )
721         return *fList;
722     return entryList( nameFilt, filterSpec, sortSpec );
723 }
724
725 /*!
726   Returns a list of the names of all files and directories in the directory
727   indicated by the setSorting(), setFilter() and setNameFilter()
728   specifications.
729
730   The filter and sorting specifications can be overridden using the
731   \e nameFilter, \e filterSpec and \e sortSpec arguments.
732
733   Returns and empty list if the directory is unreadable or does not exist.
734
735   \sa entryInfoList(), setNameFilter(), setSorting(), setFilter(),
736         encodedEntryList()
737 */
738
739 QStringList QDir::entryList( const QString &nameFilter,
740                                  int filterSpec, int sortSpec ) const
741 {
742     if ( filterSpec == (int)DefaultFilter )
743         filterSpec = filtS;
744     if ( sortSpec == (int)DefaultSort )
745         sortSpec = sortS;
746     QDir *that = (QDir*)this;                   // mutable function
747     if ( that->readDirEntries(nameFilter, filterSpec, sortSpec) )
748         return *that->fList;
749     else
750         return QStringList();
751 }
752
753 /*!
754   Returns a list of QFileInfo objects for all files and directories in
755   the directory pointed to using the setSorting(), setFilter() and
756   setNameFilter() specifications.
757
758   The filter and sorting specifications can be overridden using the
759   \e filterSpec and \e sortSpec arguments.
760
761   Returns 0 if the directory is unreadable or does not exist.
762
763   The returned pointer is a const pointer to a QFileInfoList. The list is
764   owned by the QDir object and will be reused on the next call to
765   entryInfoList() for the same QDir instance. If you want to keep the
766   entries of the list after a subsequent call to this function you will
767   need to copy them.
768
769   \sa entryList(), setNameFilter(), setSorting(), setFilter()
770 */
771
772 const QFileInfoList *QDir::entryInfoList( int filterSpec, int sortSpec ) const
773 {
774     if ( !dirty && filterSpec == (int)DefaultFilter &&
775                    sortSpec   == (int)DefaultSort )
776         return fiList;
777     return entryInfoList( nameFilt, filterSpec, sortSpec );
778 }
779
780 /*!
781   Returns a list of QFileInfo objects for all files and directories in
782   the directory pointed to using the setSorting(), setFilter() and
783   setNameFilter() specifications.
784
785   The filter and sorting specifications can be overridden using the
786   \e nameFilter, \e filterSpec and \e sortSpec arguments.
787
788   Returns 0 if the directory is unreadable or does not exist.
789
790   The returned pointer is a const pointer to a QFileInfoList. The list is
791   owned by the QDir object and will be reused on the next call to
792   entryInfoList() for the same QDir instance. If you want to keep the
793   entries of the list after a subsequent call to this function you will
794   need to copy them.
795
796   \sa entryList(), setNameFilter(), setSorting(), setFilter()
797 */
798
799 const QFileInfoList *QDir::entryInfoList( const QString &nameFilter,
800                                           int filterSpec, int sortSpec ) const
801 {
802     if ( filterSpec == (int)DefaultFilter )
803         filterSpec = filtS;
804     if ( sortSpec == (int)DefaultSort )
805         sortSpec = sortS;
806     QDir *that = (QDir*)this;                   // mutable function
807     if ( that->readDirEntries(nameFilter, filterSpec, sortSpec) )
808         return that->fiList;
809     else
810         return 0;
811 }
812
813 /*!
814   Returns TRUE if the directory exists. (If a file with the same
815   name is found this function will of course return FALSE).
816
817   \sa QFileInfo::exists(), QFile::exists()
818 */
819
820 bool QDir::exists() const
821 {
822     QFileInfo fi( dPath );
823     return fi.exists() && fi.isDir();
824 }
825
826 /*!
827   Returns TRUE if the directory path is relative to the current directory,
828   FALSE if the path is absolute (e.g. under UNIX a path is relative if it
829   does not start with a '/').
830
831   According to Einstein this function should always return TRUE.
832
833   \sa convertToAbs()
834 */
835
836 bool QDir::isRelative() const
837 {
838     return isRelativePath( dPath );
839 }
840
841 /*!
842   Converts the directory path to an absolute path. If it is already
843   absolute nothing is done.
844
845   \sa isRelative()
846 */
847
848 void QDir::convertToAbs()
849 {
850     dPath = absPath();
851 }
852
853 /*!
854   Makes a copy of d and assigns it to this QDir.
855 */
856
857 QDir &QDir::operator=( const QDir &d )
858 {
859     dPath    = d.dPath;
860     delete fList;
861     fList    = 0;
862     delete fiList;
863     fiList   = 0;
864     nameFilt = d.nameFilt;
865     dirty    = TRUE;
866     allDirs  = d.allDirs;
867     filtS    = d.filtS;
868     sortS    = d.sortS;
869     return *this;
870 }
871
872 /*!
873   Sets the directory path to be the given path.
874 */
875
876 QDir &QDir::operator=( const QString &path )
877 {
878     dPath = cleanDirPath( path );
879     dirty = TRUE;
880     return *this;
881 }
882
883
884 /*!
885   \fn bool QDir::operator!=( const QDir &d ) const
886   Returns TRUE if the \e d and this dir have different path or
887   different sort/filter settings, otherwise FALSE.
888 */
889
890 /*!
891   Returns TRUE if the \e d and this dir have the same path and all sort
892   and filter settings are equal, otherwise FALSE.
893 */
894
895 bool QDir::operator==( const QDir &d ) const
896 {
897     return dPath    == d.dPath &&
898            nameFilt == d.nameFilt &&
899            allDirs  == d.allDirs &&
900            filtS    == d.filtS &&
901            sortS    == d.sortS;
902 }
903
904
905 /*!
906   Removes a file.
907
908   If \e acceptAbsPath is TRUE a path starting with a separator ('/')
909   will remove the file with the absolute path, if \e acceptAbsPath is FALSE
910   any number of separators at the beginning of \e fileName will be removed.
911
912   Returns TRUE if successful, otherwise FALSE.
913 */
914
915 bool QDir::remove( const QString &fileName, bool acceptAbsPath )
916 {
917     if ( fileName.isEmpty() ) {
918 #if defined(CHECK_NULL)
919         qWarning( "QDir::remove: Empty or null file name" );
920 #endif
921         return FALSE;
922     }
923     QString p = filePath( fileName, acceptAbsPath );
924     return QFile::remove( p );
925 }
926
927 /*!
928   Checks for existence of a file.
929
930   If \e acceptAbsPaths is TRUE a path starting with a separator ('/')
931   will check the file with the absolute path, if \e acceptAbsPath is FALSE
932   any number of separators at the beginning of \e name will be removed.
933
934   Returns TRUE if the file exists, otherwise FALSE.
935
936   \sa QFileInfo::exists(), QFile::exists()
937 */
938
939 bool QDir::exists( const QString &name, bool acceptAbsPath )
940 {
941     if ( name.isEmpty() ) {
942 #if defined(CHECK_NULL)
943         qWarning( "QDir::exists: Empty or null file name" );
944 #endif
945         return FALSE;
946     }
947     QString tmp = filePath( name, acceptAbsPath );
948     return QFile::exists( tmp );
949 }
950
951 /*!
952   Returns the native directory separator; '/' under UNIX and '\' under
953   MS-DOS, Windows NT and OS/2.
954
955   You do not need to use this function to build file paths. If you always
956   use '/', Qt will translate your paths to conform to the underlying
957   operating system.
958 */
959
960 char QDir::separator()
961 {
962 #if defined(_OS_UNIX_)
963     return '/';
964 #elif defined (_OS_FATFS_)
965     return '\\';
966 #elif defined (_OS_MAC_)
967     return ':';
968 #else
969     return '/';
970 #endif
971 }
972
973 /*!
974   Returns the current directory.
975   \sa currentDirPath(), QDir::QDir()
976 */
977
978 QDir QDir::current()
979 {
980     return QDir( currentDirPath() );
981 }
982
983 /*!
984   Returns the home directory.
985   \sa homeDirPath()
986 */
987
988 QDir QDir::home()
989 {
990     return QDir( homeDirPath() );
991 }
992
993 /*!
994   Returns the root directory.
995   \sa rootDirPath() drives()
996 */
997
998 QDir QDir::root()
999 {
1000     return QDir( rootDirPath() );
1001 }
1002
1003 /*!
1004   \fn QString QDir::homeDirPath()
1005
1006   Returns the absolute path for the user's home directory,
1007   \sa home()
1008 */
1009
1010 QStringList qt_makeFilterList( const QString &filter )
1011 {
1012     if ( filter.isEmpty() )
1013         return QStringList();
1014
1015     QChar sep( ';' );
1016     int i = filter.find( sep, 0 );
1017     if ( i == -1 && filter.find( ' ', 0 ) != -1 )
1018         sep = QChar( ' ' );
1019
1020     QStringList lst = QStringList::split( sep, filter );
1021     QStringList lst2;
1022     QStringList::Iterator it = lst.begin();
1023
1024     for ( ; it != lst.end(); ++it ) {
1025         QString s = *it;
1026         lst2 << s.stripWhiteSpace();
1027     }
1028     return lst2;
1029 }
1030
1031 /*!
1032   Returns TRUE if the \e fileName matches one of the wildcards in the list \e filters.
1033   \sa QRegExp
1034 */
1035
1036 bool QDir::match( const QStringList &filters, const QString &fileName )
1037 {
1038     QStringList::ConstIterator sit = filters.begin();
1039     bool matched = FALSE;
1040     for ( ; sit != filters.end(); ++sit ) {
1041         QRegExp regexp( (*sit).data(), FALSE, TRUE );
1042         if ( regexp.match( fileName.data() ) != -1 ) {
1043             matched = TRUE;
1044             break;
1045         }
1046     }
1047
1048     return matched;
1049 }
1050
1051 /*!
1052   Returns TRUE if the \e fileName matches the wildcard \e filter.
1053   \a Filter may also contain multiple wildcards separated by spaces or
1054   semicolons.
1055   \sa QRegExp
1056 */
1057
1058 bool QDir::match( const QString &filter, const QString &fileName )
1059 {
1060     QStringList lst = qt_makeFilterList( filter );
1061     return match( lst, fileName );
1062 }
1063
1064
1065 /*!
1066   Removes all multiple directory separators ('/') and resolves
1067   any "." or ".." found in the path.
1068
1069   Symbolic links are kept.  This function does not return the
1070   canonical path, but rather the most simplified version of the input.
1071   "../stuff" becomes "stuff", "stuff/../nonsense" becomes "nonsense"
1072   and "\\stuff\\more\\..\\nonsense" becomes "\\stuff\\nonsense".
1073
1074   \sa absPath() canonicalPath()
1075 */
1076
1077 QString QDir::cleanDirPath( const QString &filePath )
1078 {
1079     QString name = filePath;
1080     QString newPath;
1081
1082     if ( name.isEmpty() )
1083         return name;
1084
1085     slashify( name );
1086
1087     bool addedSeparator;
1088     if ( isRelativePath(name) ) {
1089         addedSeparator = TRUE;
1090         name.insert( 0, '/' );
1091     } else {
1092         addedSeparator = FALSE;
1093     }
1094
1095     int ePos, pos, upLevel;
1096
1097     pos = ePos = name.length();
1098     upLevel = 0;
1099     int len;
1100
1101     while ( pos && (pos = name.findRev('/',--pos)) != -1 ) {
1102         len = ePos - pos - 1;
1103         if ( len == 2 && name.at(pos + 1) == '.'
1104                       && name.at(pos + 2) == '.' ) {
1105             upLevel++;
1106         } else {
1107             if ( len != 0 && (len != 1 || name.at(pos + 1) != '.') ) {
1108                 if ( !upLevel )
1109                     newPath = QString::fromLatin1("/")
1110                         + name.mid(pos + 1, len) + newPath;
1111                 else
1112                     upLevel--;
1113             }
1114         }
1115         ePos = pos;
1116     }
1117     if ( addedSeparator ) {
1118         while ( upLevel-- )
1119             newPath.insert( 0, QString::fromLatin1("/..") );
1120         if ( !newPath.isEmpty() )
1121             newPath.remove( 0, 1 );
1122         else
1123             newPath = QString::fromLatin1(".");
1124     } else {
1125         if ( newPath.isEmpty() )
1126             newPath = QString::fromLatin1("/");
1127 #if defined(_OS_FATFS_) || defined(_OS_OS2EMX_)
1128         if ( name[0] == '/' ) {
1129             if ( name[1] == '/' )               // "\\machine\x\ ..."
1130                 newPath.insert( 0, '/' );
1131         } else {
1132             newPath = name.left(2) + newPath;
1133         }
1134 #endif
1135     }
1136     return newPath;
1137 }
1138
1139 int qt_cmp_si_sortSpec;
1140
1141 #if defined(Q_C_CALLBACKS)
1142 extern "C" {
1143 #endif
1144
1145 int qt_cmp_si( const void *n1, const void *n2 )
1146 {
1147     if ( !n1 || !n2 )
1148         return 0;
1149
1150     QDirSortItem* f1 = (QDirSortItem*)n1;
1151     QDirSortItem* f2 = (QDirSortItem*)n2;
1152
1153     if ( qt_cmp_si_sortSpec & QDir::DirsFirst )
1154         if ( f1->item->isDir() != f2->item->isDir() )
1155             return f1->item->isDir() ? -1 : 1;
1156
1157     int r = 0;
1158     int sortBy = qt_cmp_si_sortSpec & QDir::SortByMask;
1159
1160     switch ( sortBy ) {
1161       case QDir::Time:
1162         r = f1->item->lastModified().secsTo(f2->item->lastModified());
1163         break;
1164       case QDir::Size:
1165         r = f2->item->size() - f1->item->size();
1166         break;
1167       default:
1168         ;
1169     }
1170
1171     if ( r == 0 && sortBy != QDir::Unsorted ) {
1172         // Still not sorted - sort by name
1173         bool ic = qt_cmp_si_sortSpec & QDir::IgnoreCase;
1174
1175         if ( f1->filename_cache.isNull() )
1176             f1->filename_cache = ic ? f1->item->fileName().lower()
1177                                     : f1->item->fileName();
1178         if ( f2->filename_cache.isNull() )
1179             f2->filename_cache = ic ? f2->item->fileName().lower()
1180                                     : f2->item->fileName();
1181
1182         r = f1->filename_cache.compare(f2->filename_cache);
1183     }
1184
1185     if ( r == 0 ) {
1186         // Enforce an order - the order the items appear in the array
1187         r = (int)((char*)n1 - (char*)n2);
1188     }
1189
1190     if ( qt_cmp_si_sortSpec & QDir::Reversed )
1191         return -r;
1192     else
1193         return r;
1194 }
1195
1196 #if defined(Q_C_CALLBACKS)
1197 }
1198 #endif
1199
1200 #endif // QT_NO_DIR