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