1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
3 #include "kwsysPrivate.h"
4 #include KWSYS_HEADER(Directory.hxx)
6 #include KWSYS_HEADER(Configure.hxx)
8 #include KWSYS_HEADER(Encoding.hxx)
10 #include KWSYS_HEADER(SystemTools.hxx)
12 // Work-around CMake dependency scanning limitation. This must
13 // duplicate the above list of headers.
15 # include "Configure.hxx.in"
16 # include "Directory.hxx.in"
17 # include "Encoding.hxx.in"
24 #if defined(_WIN32) && !defined(__CYGWIN__)
33 # include <sys/stat.h>
34 # include <sys/types.h>
37 namespace KWSYS_NAMESPACE {
39 class DirectoryInternals
45 #if defined(_WIN32) && !defined(__CYGWIN__)
46 _wfinddata_t FindData;
48 FileData(std::string name
49 #if defined(_WIN32) && !defined(__CYGWIN__)
54 : Name(std::move(name))
55 #if defined(_WIN32) && !defined(__CYGWIN__)
56 , FindData(std::move(data))
62 std::vector<FileData> Files;
64 // Path to Open'ed directory
68 Directory::Directory()
70 this->Internal = new DirectoryInternals;
73 Directory::Directory(Directory&& other)
75 this->Internal = other.Internal;
76 other.Internal = nullptr;
79 Directory& Directory::operator=(Directory&& other)
81 std::swap(this->Internal, other.Internal);
85 Directory::~Directory()
87 delete this->Internal;
90 unsigned long Directory::GetNumberOfFiles() const
92 return static_cast<unsigned long>(this->Internal->Files.size());
95 const char* Directory::GetFile(unsigned long dindex) const
97 return this->Internal->Files[dindex].Name.c_str();
100 std::string const& Directory::GetFileName(std::size_t i) const
102 return this->Internal->Files[i].Name;
105 std::string Directory::GetFilePath(std::size_t i) const
107 std::string abs = this->Internal->Path;
108 if (!abs.empty() && abs.back() != '/') {
111 abs += this->Internal->Files[i].Name;
115 bool Directory::FileIsDirectory(std::size_t i) const
117 #if defined(_WIN32) && !defined(__CYGWIN__)
118 _wfinddata_t const& data = this->Internal->Files[i].FindData;
119 return (data.attrib & FILE_ATTRIBUTE_DIRECTORY) != 0;
121 std::string const& path = this->GetFilePath(i);
122 return kwsys::SystemTools::FileIsDirectory(path);
126 bool Directory::FileIsSymlink(std::size_t i) const
128 std::string const& path = this->GetFilePath(i);
129 #if defined(_WIN32) && !defined(__CYGWIN__)
130 _wfinddata_t const& data = this->Internal->Files[i].FindData;
131 return kwsys::SystemTools::FileIsSymlinkWithAttr(
132 Encoding::ToWindowsExtendedPath(path), data.attrib);
134 return kwsys::SystemTools::FileIsSymlink(path);
138 const char* Directory::GetPath() const
140 return this->Internal->Path.c_str();
143 void Directory::Clear()
145 this->Internal->Path.resize(0);
146 this->Internal->Files.clear();
149 } // namespace KWSYS_NAMESPACE
151 // First Windows platforms
153 #if defined(_WIN32) && !defined(__CYGWIN__)
155 namespace KWSYS_NAMESPACE {
157 Status Directory::Load(std::string const& name, std::string* errorMessage)
163 size_t n = name.size();
164 if (name.back() == '/' || name.back() == '\\') {
165 bufLength = n + 1 + 1;
166 buf = new char[bufLength];
167 snprintf(buf, bufLength, "%s*", name.c_str());
169 // Make sure the slashes in the wildcard suffix are consistent with the
171 bufLength = n + 2 + 1;
172 buf = new char[bufLength];
173 if (name.find('\\') != std::string::npos) {
174 snprintf(buf, bufLength, "%s\\*", name.c_str());
176 snprintf(buf, bufLength, "%s/*", name.c_str());
179 struct _wfinddata_t data; // data of current file
181 // Now put them into the file array
183 _wfindfirst((wchar_t*)Encoding::ToWindowsExtendedPath(buf).c_str(), &data);
186 if (srchHandle == -1) {
187 Status status = Status::POSIX_errno();
189 *errorMessage = status.GetString();
194 // Loop through names
196 this->Internal->Files.emplace_back(Encoding::ToNarrow(data.name), data);
197 } while (_wfindnext(srchHandle, &data) != -1);
198 this->Internal->Path = name;
199 if (_findclose(srchHandle) == -1) {
200 Status status = Status::POSIX_errno();
202 *errorMessage = status.GetString();
206 return Status::Success();
209 unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
210 std::string* errorMessage)
215 size_t n = name.size();
216 if (name.back() == '/') {
217 bufLength = n + 1 + 1;
218 buf = new char[n + 1 + 1];
219 snprintf(buf, bufLength, "%s*", name.c_str());
221 bufLength = n + 2 + 1;
222 buf = new char[n + 2 + 1];
223 snprintf(buf, bufLength, "%s/*", name.c_str());
225 struct _wfinddata_t data; // data of current file
227 // Now put them into the file array
228 srchHandle = _wfindfirst((wchar_t*)Encoding::ToWide(buf).c_str(), &data);
231 if (srchHandle == -1) {
233 if (unsigned int errorId = GetLastError()) {
234 LPSTR message = nullptr;
235 DWORD size = FormatMessageA(
236 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
237 FORMAT_MESSAGE_IGNORE_INSERTS,
238 nullptr, errorId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
239 (LPSTR)&message, 0, nullptr);
240 *errorMessage = std::string(message, size);
243 *errorMessage = "Unknown error.";
249 // Loop through names
250 unsigned long count = 0;
253 } while (_wfindnext(srchHandle, &data) != -1);
254 _findclose(srchHandle);
258 } // namespace KWSYS_NAMESPACE
262 // Now the POSIX style directory access
264 # include <sys/types.h>
270 // PGI with glibc has trouble with dirent and large file support:
271 // http://www.pgroup.com/userforum/viewtopic.php?
272 // p=1992&sid=f16167f51964f1a68fe5041b8eb213b6
273 // Work around the problem by mapping dirent the same way as readdir.
274 # if defined(__PGI) && defined(__GLIBC__)
275 # define kwsys_dirent_readdir dirent
276 # define kwsys_dirent_readdir64 dirent64
277 # define kwsys_dirent kwsys_dirent_lookup(readdir)
278 # define kwsys_dirent_lookup(x) kwsys_dirent_lookup_delay(x)
279 # define kwsys_dirent_lookup_delay(x) kwsys_dirent_##x
281 # define kwsys_dirent dirent
284 namespace KWSYS_NAMESPACE {
286 Status Directory::Load(std::string const& name, std::string* errorMessage)
291 DIR* dir = opendir(name.c_str());
294 if (errorMessage != nullptr) {
295 *errorMessage = std::string(strerror(errno));
297 return Status::POSIX_errno();
301 for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) {
302 this->Internal->Files.emplace_back(d->d_name);
305 if (errorMessage != nullptr) {
306 *errorMessage = std::string(strerror(errno));
308 return Status::POSIX_errno();
311 this->Internal->Path = name;
313 return Status::Success();
316 unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
317 std::string* errorMessage)
320 DIR* dir = opendir(name.c_str());
323 if (errorMessage != nullptr) {
324 *errorMessage = std::string(strerror(errno));
329 unsigned long count = 0;
330 for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) {
334 if (errorMessage != nullptr) {
335 *errorMessage = std::string(strerror(errno));
344 } // namespace KWSYS_NAMESPACE