Drop useless comment marker
[TortoiseGit.git] / src / Utils / DirFileEnum.cpp
blob51c2242ab5a4cb7805ea775025f52f12dcfbed02
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2015-2020 - TortoiseGit
4 // Copyright (C) 2005-2006, 2009-2010 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
20 #include "DirFileEnum.h"
21 #include "StringUtils.h"
23 CSimpleFileFind::CSimpleFileFind(const CString &sPath, LPCTSTR pPattern)
24 : m_dError(ERROR_SUCCESS)
25 , m_bFirst(TRUE)
26 , m_sPathPrefix(sPath)
28 // Add a trailing \ to m_sPathPrefix if it is missing.
29 // Do not add one to "C:" since "C:" and "C:\" are different.
30 int len = m_sPathPrefix.GetLength();
31 if (len != 0)
33 TCHAR ch = sPath[len-1];
34 if (ch != '\\' && (ch != ':' || len != 2))
35 m_sPathPrefix += "\\";
37 if (len >= 248 && (CStringUtils::StartsWith(m_sPathPrefix, L"\\\\?\\")))
38 m_hFindFile = ::FindFirstFileEx(static_cast<LPCTSTR>(L"\\\\?\\" + m_sPathPrefix + pPattern), FindExInfoBasic, &m_FindFileData, FindExSearchNameMatch, nullptr, FIND_FIRST_EX_LARGE_FETCH);
39 else
40 m_hFindFile = ::FindFirstFileEx(static_cast<LPCTSTR>(m_sPathPrefix + pPattern), FindExInfoBasic, &m_FindFileData, FindExSearchNameMatch, nullptr, FIND_FIRST_EX_LARGE_FETCH);
41 if (m_hFindFile == INVALID_HANDLE_VALUE) {
42 m_dError = ::GetLastError();
46 CSimpleFileFind::~CSimpleFileFind()
48 if (m_hFindFile != INVALID_HANDLE_VALUE)
49 ::FindClose(m_hFindFile);
52 BOOL CSimpleFileFind::FindNextFile()
54 if (m_dError)
55 return FALSE;
57 if (m_bFirst)
59 m_bFirst = FALSE;
60 return TRUE;
63 if (!::FindNextFile(m_hFindFile, &m_FindFileData))
65 m_dError = ::GetLastError();
66 return FALSE;
69 return TRUE;
72 BOOL CSimpleFileFind::FindNextFileNoDots()
74 BOOL result;
75 do {
76 result = FindNextFile();
77 } while (result && IsDots());
79 return result;
82 BOOL CSimpleFileFind::FindNextFileNoDirectories()
84 BOOL result;
85 do {
86 result = FindNextFile();
87 } while (result && IsDirectory());
89 return result;
94 * Implementation notes:
96 * This is a depth-first traversal. Directories are visited before
97 * their contents.
99 * We keep a stack of directories. The deepest directory is at the top
100 * of the stack, the originally-requested directory is at the bottom.
101 * If we come across a directory, we first return it to the user, then
102 * recurse into it. The finder at the bottom of the stack always points
103 * to the file or directory last returned to the user (except immediately
104 * after creation, when the finder points to the first valid thing we need
105 * to return, but we haven't actually returned anything yet - hence the
106 * m_bIsNew variable).
108 * Errors reading a directory are assumed to be end-of-directory, and
109 * are otherwise ignored.
111 * The "." and ".." psedo-directories are ignored for obvious reasons.
115 CDirFileEnum::CDirStackEntry::CDirStackEntry(CDirStackEntry* seNext, const CString& sDirName)
116 : CSimpleFileFind(sDirName)
117 , m_seNext(seNext)
121 CDirFileEnum::CDirStackEntry::~CDirStackEntry()
125 inline void CDirFileEnum::PopStack()
127 CDirStackEntry* seToDelete = m_seStack;
128 m_seStack = seToDelete->m_seNext;
129 delete seToDelete;
132 inline void CDirFileEnum::PushStack(const CString& sDirName)
134 m_seStack = new CDirStackEntry(m_seStack,sDirName);
137 CDirFileEnum::CDirFileEnum(const CString& sDirName)
138 : m_seStack(nullptr)
139 , m_bIsNew(TRUE)
141 PushStack(sDirName);
144 CDirFileEnum::~CDirFileEnum()
146 while (m_seStack)
147 PopStack();
150 BOOL CDirFileEnum::NextFile(CString &sResult, bool* pbIsDirectory, bool bRecurse /* = true */)
152 if (m_bIsNew)
154 // Special-case first time - haven't found anything yet,
155 // so don't do recurse-into-directory check.
156 m_bIsNew = FALSE;
158 else if (m_seStack && m_seStack->IsDirectory() && bRecurse)
159 PushStack(m_seStack->GetFilePath());
161 while (m_seStack && !m_seStack->FindNextFileNoDots())
163 // No more files in this directory, try parent.
164 PopStack();
167 if (m_seStack)
169 sResult = m_seStack->GetFilePath();
170 if (pbIsDirectory)
171 *pbIsDirectory = m_seStack->IsDirectory();
172 return TRUE;
175 return FALSE;