[llvm-commits] [llvm] r120989 - in /llvm/trunk: include/llvm/Support/FileSystem.h lib/Support/PathV2.cpp lib/Support/Windows/PathV2.inc lib/Support/Windows/Windows.h unittests/Support/Path.cpp

Michael J. Spencer bigcheesegs at gmail.com
Sun Dec 5 20:28:42 PST 2010


Author: mspencer
Date: Sun Dec  5 22:28:42 2010
New Revision: 120989

URL: http://llvm.org/viewvc/llvm-project?rev=120989&view=rev
Log:
Support/FileSystem: Add directory_iterator implementation.

Modified:
    llvm/trunk/include/llvm/Support/FileSystem.h
    llvm/trunk/lib/Support/PathV2.cpp
    llvm/trunk/lib/Support/Windows/PathV2.inc
    llvm/trunk/lib/Support/Windows/Windows.h
    llvm/trunk/unittests/Support/Path.cpp

Modified: llvm/trunk/include/llvm/Support/FileSystem.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileSystem.h?rev=120989&r1=120988&r2=120989&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FileSystem.h (original)
+++ llvm/trunk/include/llvm/Support/FileSystem.h Sun Dec  5 22:28:42 2010
@@ -544,19 +544,29 @@
 
 public:
   explicit directory_entry(const Twine &path, file_status st = file_status(),
-                                       file_status symlink_st = file_status());
+                                       file_status symlink_st = file_status())
+    : Path(path.str())
+    , Status(st)
+    , SymlinkStatus(symlink_st) {}
+
+  directory_entry() {}
 
   void assign(const Twine &path, file_status st = file_status(),
-                          file_status symlink_st = file_status());
+                          file_status symlink_st = file_status()) {
+    Path = path.str();
+    Status = st;
+    SymlinkStatus = symlink_st;
+  }
+
   void replace_filename(const Twine &filename, file_status st = file_status(),
                               file_status symlink_st = file_status());
 
-  const SmallVectorImpl<char> &path() const;
+  StringRef path() const { return Path; }
   error_code status(file_status &result) const;
   error_code symlink_status(file_status &result) const;
 
-  bool operator==(const directory_entry& rhs) const;
-  bool operator!=(const directory_entry& rhs) const;
+  bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; }
+  bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); }
   bool operator< (const directory_entry& rhs) const;
   bool operator<=(const directory_entry& rhs) const;
   bool operator> (const directory_entry& rhs) const;
@@ -567,16 +577,41 @@
 /// operator++ because we need an error_code. If it's really needed we can make
 /// it call report_fatal_error on error.
 class directory_iterator {
-  // implementation directory iterator status
+  intptr_t IterationHandle;
+  directory_entry CurrentEntry;
 
-public:
-  explicit directory_iterator(const Twine &path, error_code &ec);
-  // No operator++ because we need error_code.
-  directory_iterator &increment(error_code &ec);
+  // Platform implementations implement these functions to handle iteration.
+  friend error_code directory_iterator_construct(directory_iterator& it,
+                                                 const StringRef &path);
+  friend error_code directory_iterator_increment(directory_iterator& it);
+  friend error_code directory_iterator_destruct(directory_iterator& it);
 
-  const directory_entry &operator*() const;
-  const directory_entry *operator->() const;
+public:
+  explicit directory_iterator(const Twine &path, error_code &ec)
+  : IterationHandle(0) {
+    SmallString<128> path_storage;
+    ec = directory_iterator_construct(*this, path.toStringRef(path_storage));
+  }
+
+  /// Construct end iterator.
+  directory_iterator() : IterationHandle(0) {}
+
+  ~directory_iterator() {
+    directory_iterator_destruct(*this);
+  }
 
+  // No operator++ because we need error_code.
+  directory_iterator &increment(error_code &ec) {
+    ec = directory_iterator_increment(*this);
+    return *this;
+  }
+
+  const directory_entry &operator*() const { return CurrentEntry; }
+  const directory_entry *operator->() const { return &CurrentEntry; };
+
+  bool operator!=(const directory_iterator &RHS) const {
+    return CurrentEntry != RHS.CurrentEntry;
+  }
   // Other members as required by
   // C++ Std, 24.1.1 Input iterators [input.iterators]
 };

Modified: llvm/trunk/lib/Support/PathV2.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/PathV2.cpp?rev=120989&r1=120988&r2=120989&view=diff
==============================================================================
--- llvm/trunk/lib/Support/PathV2.cpp (original)
+++ llvm/trunk/lib/Support/PathV2.cpp Sun Dec  5 22:28:42 2010
@@ -688,6 +688,16 @@
   return create_directory(p, existed);
 }
 
+void directory_entry::replace_filename(const Twine &filename, file_status st,
+                                       file_status symlink_st) {
+  SmallString<128> path(Path.begin(), Path.end());
+  path::remove_filename(path);
+  path::append(path, filename);
+  Path = path.str();
+  Status = st;
+  SymlinkStatus = symlink_st;
+}
+
 } // end namespace fs
 } // end namespace sys
 } // end namespace llvm

Modified: llvm/trunk/lib/Support/Windows/PathV2.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/PathV2.inc?rev=120989&r1=120988&r2=120989&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Windows/PathV2.inc (original)
+++ llvm/trunk/lib/Support/Windows/PathV2.inc Sun Dec  5 22:28:42 2010
@@ -121,6 +121,15 @@
   typedef ScopedHandle<HCRYPTPROV, HCRYPTPROV(INVALID_HANDLE_VALUE),
                        BOOL (WINAPI*)(HCRYPTPROV), CryptReleaseContext>
     ScopedCryptContext;
+  bool is_separator(const wchar_t value) {
+    switch (value) {
+    case L'\\':
+    case L'/':
+      return true;
+    default:
+      return false;
+    }
+  }
 }
 
 namespace llvm {
@@ -598,6 +607,74 @@
   result_fd = fd;
   return success;
 }
+
+error_code directory_iterator_construct(directory_iterator& it,
+                                        const StringRef &path) {
+  SmallVector<wchar_t, 128> path_utf16;
+
+  if (error_code ec = UTF8ToUTF16(path,
+                                  path_utf16))
+    return ec;
+
+  // Convert path to the format that Windows is happy with.
+  if (path_utf16.size() > 0 &&
+      !is_separator(path_utf16[path.size() - 1]) &&
+      path_utf16[path.size() - 1] != L':') {
+    path_utf16.push_back(L'\\');
+    path_utf16.push_back(L'*');
+  } else {
+    path_utf16.push_back(L'*');
+  }
+
+  //  Get the first directory entry.
+  WIN32_FIND_DATAW FirstFind;
+  ScopedFindHandle FindHandle(::FindFirstFileW(path_utf16.c_str(), &FirstFind));
+  if (!FindHandle)
+    return windows_error(::GetLastError());
+
+  // Construct the current directory entry.
+  SmallString<128> directory_entry_path_utf8;
+  if (error_code ec = UTF16ToUTF8(FirstFind.cFileName,
+                                  ::wcslen(FirstFind.cFileName),
+                                  directory_entry_path_utf8))
+    return ec;
+
+  it.IterationHandle = intptr_t(FindHandle.take());
+  it.CurrentEntry = directory_entry(path);
+  it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
+
+  return success;
+}
+
+error_code directory_iterator_destruct(directory_iterator& it) {
+  if (it.IterationHandle != 0)
+    // Closes the handle if it's valid.
+    ScopedFindHandle close(HANDLE(it.IterationHandle));
+  it.IterationHandle = 0;
+  it.CurrentEntry = directory_entry();
+  return success;
+}
+
+error_code directory_iterator_increment(directory_iterator& it) {
+  WIN32_FIND_DATAW FindData;
+  if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) {
+    error_code ec = windows_error(::GetLastError());
+    // Check for end.
+    if (ec == windows_error::no_more_files)
+      return directory_iterator_destruct(it);
+    return ec;
+  }
+
+  SmallString<128> directory_entry_path_utf8;
+  if (error_code ec = UTF16ToUTF8(FindData.cFileName,
+                                  ::wcslen(FindData.cFileName),
+                                  directory_entry_path_utf8))
+    return ec;
+
+  it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8));
+  return success;
+}
+
 } // end namespace fs
 } // end namespace sys
 } // end namespace llvm

Modified: llvm/trunk/lib/Support/Windows/Windows.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Windows.h?rev=120989&r1=120988&r2=120989&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Windows/Windows.h (original)
+++ llvm/trunk/lib/Support/Windows/Windows.h Sun Dec  5 22:28:42 2010
@@ -94,7 +94,11 @@
     return Handle == InvalidHandle ? 0 : unspecified_bool_true;
   }
 
-  typedef ScopedHandle<HANDLE, INVALID_HANDLE_VALUE,
-                       BOOL (WINAPI*)(HANDLE), ::FindClose>
-    ScopedFindHandle;
+  bool operator!() const {
+    return Handle == InvalidHandle;
+  }
 };
+
+typedef ScopedHandle<HANDLE, INVALID_HANDLE_VALUE,
+                      BOOL (WINAPI*)(HANDLE), ::FindClose>
+  ScopedFindHandle;

Modified: llvm/trunk/unittests/Support/Path.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/Path.cpp?rev=120989&r1=120988&r2=120989&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/Path.cpp (original)
+++ llvm/trunk/unittests/Support/Path.cpp Sun Dec  5 22:28:42 2010
@@ -9,6 +9,7 @@
 
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/PathV2.h"
+#include "llvm/Support/ErrorHandling.h"
 
 #include "gtest/gtest.h"
 
@@ -168,6 +169,18 @@
   // Make sure Temp1 doesn't exist.
   ASSERT_FALSE(fs::exists(Twine(TempPath), TempFileExists));
   EXPECT_FALSE(TempFileExists);
+
+  // I've yet to do directory iteration on Unix.
+#ifdef LLVM_ON_WIN32
+  error_code ec;
+  for (fs::directory_iterator i(".", ec), e; i != e; i.increment(ec)) {
+    if (ec) {
+      errs() << ec.message() << '\n';
+      errs().flush();
+      report_fatal_error("Directory iteration failed!");
+    }
+  }
+#endif
 }
 
 } // anonymous namespace





More information about the llvm-commits mailing list