1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2005 - 2006 - Jon Foster
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "DirFileEnum.h"
22 CSimpleFileFind::CSimpleFileFind(const CString
&sPath
, LPCTSTR pPattern
) :
23 m_dError(ERROR_SUCCESS
),
27 // Add a trailing \ to m_sPathPrefix if it is missing.
28 // Do not add one to "C:" since "C:" and "C:\" are different.
30 int len
= m_sPathPrefix
.GetLength();
32 TCHAR ch
= sPath
[len
-1];
33 if (ch
!= '\\' && (ch
!= ':' || len
!= 2)) {
34 m_sPathPrefix
+= "\\";
39 m_hFindFile
= ::FindFirstFile((LPCTSTR
)(m_sPathPrefix
+ pPattern
), &m_FindFileData
);
40 if (m_hFindFile
== INVALID_HANDLE_VALUE
) {
41 m_dError
= ::GetLastError();
45 CSimpleFileFind::~CSimpleFileFind()
47 if (m_hFindFile
!= INVALID_HANDLE_VALUE
) {
48 ::FindClose(m_hFindFile
);
52 BOOL
CSimpleFileFind::FindNextFile()
63 if (!::FindNextFile(m_hFindFile
, &m_FindFileData
)) {
64 m_dError
= ::GetLastError();
71 BOOL
CSimpleFileFind::FindNextFileNoDots()
75 result
= FindNextFile();
76 } while (result
&& IsDots());
81 BOOL
CSimpleFileFind::FindNextFileNoDirectories()
85 result
= FindNextFile();
86 } while (result
&& IsDirectory());
93 * Implementation notes:
95 * This is a depth-first traversal. Directories are visited before
98 * We keep a stack of directories. The deepest directory is at the top
99 * of the stack, the originally-requested directory is at the bottom.
100 * If we come across a directory, we first return it to the user, then
101 * recurse into it. The finder at the bottom of the stack always points
102 * to the file or directory last returned to the user (except immediately
103 * after creation, when the finder points to the first valid thing we need
104 * to return, but we haven't actually returned anything yet - hence the
105 * m_bIsNew variable).
107 * Errors reading a directory are assumed to be end-of-directory, and
108 * are otherwise ignored.
110 * The "." and ".." psedo-directories are ignored for obvious reasons.
114 CDirFileEnum::CDirStackEntry::CDirStackEntry(CDirStackEntry
* seNext
,
115 const CString
& sDirName
)
116 : CSimpleFileFind(sDirName
),
121 CDirFileEnum::CDirStackEntry::~CDirStackEntry()
125 inline void CDirFileEnum::PopStack()
127 CDirStackEntry
* seToDelete
= m_seStack
;
128 m_seStack
= seToDelete
->m_seNext
;
132 inline void CDirFileEnum::PushStack(const CString
& sDirName
)
134 m_seStack
= new CDirStackEntry(m_seStack
,sDirName
);
137 CDirFileEnum::CDirFileEnum(const CString
& sDirName
) :
144 CDirFileEnum::~CDirFileEnum()
146 while (m_seStack
!= NULL
) {
151 BOOL
CDirFileEnum::NextFile(CString
&sResult
, bool* pbIsDirectory
)
154 // Special-case first time - haven't found anything yet,
155 // so don't do recurse-into-directory check.
157 } else if (m_seStack
&& m_seStack
->IsDirectory()) {
158 PushStack(m_seStack
->GetFilePath());
161 while (m_seStack
&& !m_seStack
->FindNextFileNoDots()) {
162 // No more files in this directory, try parent.
168 sResult
= m_seStack
->GetFilePath();
169 if(pbIsDirectory
!= NULL
)
171 *pbIsDirectory
= m_seStack
->IsDirectory();