This revision was automatically updated to reflect the committed changes.
Closed by commit rL373564: factor out an abstract base class for File (authored 
by lawrence_danna, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D68317?vs=222851&id=222962#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68317/new/

https://reviews.llvm.org/D68317

Files:
  lldb/trunk/include/lldb/Host/File.h
  lldb/trunk/scripts/Python/python-typemaps.swig
  lldb/trunk/source/API/SBDebugger.cpp
  lldb/trunk/source/API/SBFile.cpp
  lldb/trunk/source/Core/Debugger.cpp
  lldb/trunk/source/Core/StreamFile.cpp
  lldb/trunk/source/Host/common/File.cpp
  lldb/trunk/source/Host/common/FileSystem.cpp
  lldb/trunk/source/Host/posix/ConnectionFileDescriptorPosix.cpp
  lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
  
lldb/trunk/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm
  lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
  
lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
  lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
  lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
  lldb/trunk/source/Target/Process.cpp
  lldb/trunk/unittests/Host/FileTest.cpp

Index: lldb/trunk/unittests/Host/FileTest.cpp
===================================================================
--- lldb/trunk/unittests/Host/FileTest.cpp
+++ lldb/trunk/unittests/Host/FileTest.cpp
@@ -31,7 +31,7 @@
   FILE *stream = fdopen(fd, "r");
   ASSERT_TRUE(stream);
 
-  File file(stream, true);
+  NativeFile file(stream, true);
   EXPECT_EQ(file.GetWaitableHandle(), fd);
 }
 
@@ -46,7 +46,7 @@
   llvm::FileRemover remover(name);
   ASSERT_GE(fd, 0);
 
-  File file(fd, File::eOpenOptionWrite, true);
+  NativeFile file(fd, File::eOpenOptionWrite, true);
   ASSERT_TRUE(file.IsValid());
 
   FILE *stream = file.GetStream();
Index: lldb/trunk/source/API/SBDebugger.cpp
===================================================================
--- lldb/trunk/source/API/SBDebugger.cpp
+++ lldb/trunk/source/API/SBDebugger.cpp
@@ -289,7 +289,7 @@
 void SBDebugger::SetInputFileHandle(FILE *fh, bool transfer_ownership) {
   LLDB_RECORD_METHOD(void, SBDebugger, SetInputFileHandle, (FILE *, bool), fh,
                      transfer_ownership);
-  SetInputFile(std::make_shared<File>(fh, transfer_ownership));
+  SetInputFile((FileSP)std::make_shared<NativeFile>(fh, transfer_ownership));
 }
 
 // Shouldn't really be settable after initialization as this could cause lots
@@ -319,7 +319,7 @@
     // FIXME Jonas Devlieghere: shouldn't this error be propagated out to the
     // reproducer somehow if fh is NULL?
     if (fh) {
-      file_sp = std::make_shared<File>(fh, true);
+      file_sp = std::make_shared<NativeFile>(fh, true);
     }
   }
 
@@ -335,7 +335,7 @@
 void SBDebugger::SetOutputFileHandle(FILE *fh, bool transfer_ownership) {
   LLDB_RECORD_METHOD(void, SBDebugger, SetOutputFileHandle, (FILE *, bool), fh,
                      transfer_ownership);
-  SetOutputFile(std::make_shared<File>(fh, transfer_ownership));
+  SetOutputFile((FileSP)std::make_shared<NativeFile>(fh, transfer_ownership));
 }
 
 SBError SBDebugger::SetOutputFile(SBFile file) {
@@ -356,7 +356,7 @@
 void SBDebugger::SetErrorFileHandle(FILE *fh, bool transfer_ownership) {
   LLDB_RECORD_METHOD(void, SBDebugger, SetErrorFileHandle, (FILE *, bool), fh,
                      transfer_ownership);
-  SetErrorFile(std::make_shared<File>(fh, transfer_ownership));
+  SetErrorFile((FileSP)std::make_shared<NativeFile>(fh, transfer_ownership));
 }
 
 SBError SBDebugger::SetErrorFile(SBFile file) {
Index: lldb/trunk/source/API/SBFile.cpp
===================================================================
--- lldb/trunk/source/API/SBFile.cpp
+++ lldb/trunk/source/API/SBFile.cpp
@@ -21,14 +21,14 @@
 SBFile::SBFile() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBFile); }
 
 SBFile::SBFile(FILE *file, bool transfer_ownership) {
-  m_opaque_sp = std::make_shared<File>(file, transfer_ownership);
+  m_opaque_sp = std::make_shared<NativeFile>(file, transfer_ownership);
 }
 
 SBFile::SBFile(int fd, const char *mode, bool transfer_owndership) {
   LLDB_RECORD_CONSTRUCTOR(SBFile, (int, const char *, bool), fd, mode,
                           transfer_owndership);
   auto options = File::GetOptionsFromMode(mode);
-  m_opaque_sp = std::make_shared<File>(fd, options, transfer_owndership);
+  m_opaque_sp = std::make_shared<NativeFile>(fd, options, transfer_owndership);
 }
 
 SBError SBFile::Read(uint8_t *buf, size_t num_bytes, size_t *bytes_read) {
Index: lldb/trunk/source/Core/StreamFile.cpp
===================================================================
--- lldb/trunk/source/Core/StreamFile.cpp
+++ lldb/trunk/source/Core/StreamFile.cpp
@@ -25,11 +25,11 @@
 
 StreamFile::StreamFile(int fd, bool transfer_ownership) : Stream() {
   m_file_sp =
-      std::make_shared<File>(fd, File::eOpenOptionWrite, transfer_ownership);
+      std::make_shared<NativeFile>(fd, File::eOpenOptionWrite, transfer_ownership);
 }
 
 StreamFile::StreamFile(FILE *fh, bool transfer_ownership) : Stream() {
-  m_file_sp = std::make_shared<File>(fh, transfer_ownership);
+  m_file_sp = std::make_shared<NativeFile>(fh, transfer_ownership);
 }
 
 StreamFile::StreamFile(const char *path) : Stream() {
Index: lldb/trunk/source/Core/Debugger.cpp
===================================================================
--- lldb/trunk/source/Core/Debugger.cpp
+++ lldb/trunk/source/Core/Debugger.cpp
@@ -698,7 +698,7 @@
 Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
     : UserID(g_unique_id++),
       Properties(std::make_shared<OptionValueProperties>()),
-      m_input_file_sp(std::make_shared<File>(stdin, false)),
+      m_input_file_sp(std::make_shared<NativeFile>(stdin, false)),
       m_output_stream_sp(std::make_shared<StreamFile>(stdout, false)),
       m_error_stream_sp(std::make_shared<StreamFile>(stderr, false)),
       m_input_recorder(nullptr),
@@ -981,7 +981,7 @@
 
     // If there is nothing, use stdin
     if (!in)
-      in = std::make_shared<File>(stdin, false);
+      in = std::make_shared<NativeFile>(stdin, false);
   }
   // If no STDOUT has been set, then set it appropriately
   if (!out) {
Index: lldb/trunk/source/Target/Process.cpp
===================================================================
--- lldb/trunk/source/Target/Process.cpp
+++ lldb/trunk/source/Target/Process.cpp
@@ -4422,9 +4422,9 @@
 
 protected:
   Process *m_process;
-  File m_read_file;  // Read from this file (usually actual STDIN for LLDB
-  File m_write_file; // Write to this file (usually the master pty for getting
-                     // io to debuggee)
+  NativeFile m_read_file;  // Read from this file (usually actual STDIN for LLDB
+  NativeFile m_write_file; // Write to this file (usually the master pty for
+                           // getting io to debuggee)
   Pipe m_pipe;
   std::atomic<bool> m_is_running{false};
 };
Index: lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
===================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -1024,8 +1024,8 @@
   // File object knows about that.
   PythonString py_mode = GetAttributeValue("mode").AsType<PythonString>();
   auto options = File::GetOptionsFromMode(py_mode.GetString());
-  auto file = std::make_unique<File>(PyObject_AsFileDescriptor(m_py_obj),
-                                     options, false);
+  auto file = std::unique_ptr<File>(
+      new NativeFile(PyObject_AsFileDescriptor(m_py_obj), options, false));
   if (!file->IsValid())
     return nullptr;
   return file;
Index: lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
===================================================================
--- lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ lldb/trunk/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -720,9 +720,9 @@
 
   PythonDictionary &sys_module_dict = GetSysModuleDictionary();
   if (sys_module_dict.IsValid()) {
-    File in_file(in, false);
-    File out_file(out, false);
-    File err_file(err, false);
+    NativeFile in_file(in, false);
+    NativeFile out_file(out, false);
+    NativeFile err_file(err, false);
 
     lldb::FileSP in_sp;
     lldb::StreamFileSP out_sp;
Index: lldb/trunk/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm
===================================================================
--- lldb/trunk/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm
+++ lldb/trunk/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm
@@ -434,7 +434,7 @@
             file_options |= File::eOpenOptionRead;
           if ((oflag & O_RDWR) || (oflag & O_RDONLY))
             file_options |= File::eOpenOptionWrite;
-          file = std::make_shared<File>(created_fd, file_options, true);
+          file = std::make_shared<NativeFile>(created_fd, file_options, true);
           [options setValue:[NSNumber numberWithInteger:created_fd] forKey:key];
           return error; // Success
         } else {
Index: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
===================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -546,7 +546,7 @@
   int err = -1;
   int save_errno = 0;
   if (fd >= 0) {
-    File file(fd, 0, true);
+    NativeFile file(fd, 0, true);
     Status error = file.Close();
     err = 0;
     save_errno = error.GetError();
@@ -577,7 +577,7 @@
       }
 
       std::string buffer(count, 0);
-      File file(fd, File::eOpenOptionRead, false);
+      NativeFile file(fd, File::eOpenOptionRead, false);
       Status error = file.Read(static_cast<void *>(&buffer[0]), count, offset);
       const ssize_t bytes_read = error.Success() ? count : -1;
       const int save_errno = error.GetError();
@@ -609,7 +609,7 @@
     if (packet.GetChar() == ',') {
       std::string buffer;
       if (packet.GetEscapedBinaryData(buffer)) {
-        File file(fd, File::eOpenOptionWrite, false);
+        NativeFile file(fd, File::eOpenOptionWrite, false);
         size_t count = buffer.size();
         Status error =
             file.Write(static_cast<const void *>(&buffer[0]), count, offset);
Index: lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
===================================================================
--- lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
+++ lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp
@@ -881,8 +881,8 @@
 
   // TODO make PipePOSIX derive from IOObject.  This is goofy here.
   const bool transfer_ownership = false;
-  auto io_sp = IOObjectSP(
-      new File(m_waitpid_pipe.GetReadFileDescriptor(), transfer_ownership));
+  auto io_sp = IOObjectSP(new NativeFile(m_waitpid_pipe.GetReadFileDescriptor(),
+                                         transfer_ownership));
   m_waitpid_reader_handle = main_loop.RegisterReadObject(
       io_sp, [this](MainLoopBase &) { HandleWaitpidResult(); }, error);
 
Index: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
===================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -894,7 +894,7 @@
     }
 
     if (temp_fd != -1) {
-      lldb_private::File file(temp_fd, File::eOpenOptionWrite, true);
+      lldb_private::NativeFile file(temp_fd, File::eOpenOptionWrite, true);
       const size_t expr_text_len = strlen(expr_text);
       size_t bytes_written = expr_text_len;
       if (file.Write(expr_text, bytes_written).Success()) {
Index: lldb/trunk/source/Host/common/File.cpp
===================================================================
--- lldb/trunk/source/Host/common/File.cpp
+++ lldb/trunk/source/Host/common/File.cpp
@@ -85,9 +85,152 @@
 int File::kInvalidDescriptor = -1;
 FILE *File::kInvalidStream = nullptr;
 
-File::~File() { Close(); }
+Status File::Read(void *buf, size_t &num_bytes) {
+  return std::error_code(ENOTSUP, std::system_category());
+}
+Status File::Write(const void *buf, size_t &num_bytes) {
+  return std::error_code(ENOTSUP, std::system_category());
+}
+
+bool File::IsValid() const { return false; }
+
+Status File::Close() { return Flush(); }
+
+IOObject::WaitableHandle File::GetWaitableHandle() {
+  return IOObject::kInvalidHandleValue;
+}
+
+Status File::GetFileSpec(FileSpec &file_spec) const {
+  file_spec.Clear();
+  return std::error_code(ENOTSUP, std::system_category());
+}
+
+FILE *File::TakeStreamAndClear() { return nullptr; }
+
+int File::GetDescriptor() const { return kInvalidDescriptor; }
+
+FILE *File::GetStream() { return nullptr; }
+
+off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
+  if (error_ptr)
+    *error_ptr = std::error_code(ENOTSUP, std::system_category());
+  return -1;
+}
+
+off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
+  if (error_ptr)
+    *error_ptr = std::error_code(ENOTSUP, std::system_category());
+  return -1;
+}
+
+off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
+  if (error_ptr)
+    *error_ptr = std::error_code(ENOTSUP, std::system_category());
+  return -1;
+}
+
+Status File::Read(void *dst, size_t &num_bytes, off_t &offset) {
+  return std::error_code(ENOTSUP, std::system_category());
+}
+
+Status File::Write(const void *src, size_t &num_bytes, off_t &offset) {
+  return std::error_code(ENOTSUP, std::system_category());
+}
+
+Status File::Flush() { return Status(); }
+
+Status File::Sync() { return Flush(); }
+
+void File::CalculateInteractiveAndTerminal() {
+  const int fd = GetDescriptor();
+  if (!DescriptorIsValid(fd)) {
+    m_is_interactive = eLazyBoolNo;
+    m_is_real_terminal = eLazyBoolNo;
+    m_supports_colors = eLazyBoolNo;
+    return;
+  }
+  m_is_interactive = eLazyBoolNo;
+  m_is_real_terminal = eLazyBoolNo;
+#if defined(_WIN32)
+  if (_isatty(fd)) {
+    m_is_interactive = eLazyBoolYes;
+    m_is_real_terminal = eLazyBoolYes;
+#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+    m_supports_colors = eLazyBoolYes;
+#endif
+  }
+#else
+  if (isatty(fd)) {
+    m_is_interactive = eLazyBoolYes;
+    struct winsize window_size;
+    if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
+      if (window_size.ws_col > 0) {
+        m_is_real_terminal = eLazyBoolYes;
+        if (llvm::sys::Process::FileDescriptorHasColors(fd))
+          m_supports_colors = eLazyBoolYes;
+      }
+    }
+  }
+#endif
+}
+
+bool File::GetIsInteractive() {
+  if (m_is_interactive == eLazyBoolCalculate)
+    CalculateInteractiveAndTerminal();
+  return m_is_interactive == eLazyBoolYes;
+}
+
+bool File::GetIsRealTerminal() {
+  if (m_is_real_terminal == eLazyBoolCalculate)
+    CalculateInteractiveAndTerminal();
+  return m_is_real_terminal == eLazyBoolYes;
+}
+
+bool File::GetIsTerminalWithColors() {
+  if (m_supports_colors == eLazyBoolCalculate)
+    CalculateInteractiveAndTerminal();
+  return m_supports_colors == eLazyBoolYes;
+}
+
+size_t File::Printf(const char *format, ...) {
+  va_list args;
+  va_start(args, format);
+  size_t result = PrintfVarArg(format, args);
+  va_end(args);
+  return result;
+}
+
+size_t File::PrintfVarArg(const char *format, va_list args) {
+  size_t result = 0;
+  char *s = nullptr;
+  result = vasprintf(&s, format, args);
+  if (s != nullptr) {
+    if (result > 0) {
+      size_t s_len = result;
+      Write(s, s_len);
+      result = s_len;
+    }
+    free(s);
+  }
+  return result;
+}
+
+uint32_t File::GetPermissions(Status &error) const {
+  int fd = GetDescriptor();
+  if (!DescriptorIsValid(fd)) {
+    error = std::error_code(ENOTSUP, std::system_category());
+    return 0;
+  }
+  struct stat file_stats;
+  if (::fstat(fd, &file_stats) == -1) {
+    error.SetErrorToErrno();
+    return 0;
+  }
+  error.Clear();
+  return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+}
 
-int File::GetDescriptor() const {
+int NativeFile::GetDescriptor() const {
   if (DescriptorIsValid())
     return m_descriptor;
 
@@ -105,9 +248,11 @@
   return kInvalidDescriptor;
 }
 
-IOObject::WaitableHandle File::GetWaitableHandle() { return GetDescriptor(); }
+IOObject::WaitableHandle NativeFile::GetWaitableHandle() {
+  return GetDescriptor();
+}
 
-FILE *File::GetStream() {
+FILE *NativeFile::GetStream() {
   if (!StreamIsValid()) {
     if (DescriptorIsValid()) {
       const char *mode = GetStreamOpenModeFromOptions(m_options);
@@ -139,23 +284,7 @@
   return m_stream;
 }
 
-uint32_t File::GetPermissions(Status &error) const {
-  int fd = GetDescriptor();
-  if (fd != kInvalidDescriptor) {
-    struct stat file_stats;
-    if (::fstat(fd, &file_stats) == -1)
-      error.SetErrorToErrno();
-    else {
-      error.Clear();
-      return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
-    }
-  } else {
-    error.SetErrorString("invalid file descriptor");
-  }
-  return 0;
-}
-
-Status File::Close() {
+Status NativeFile::Close() {
   Status error;
   if (StreamIsValid()) {
     if (m_own_stream) {
@@ -166,7 +295,6 @@
         error.SetErrorToErrno();
     }
   }
-
   if (DescriptorIsValid() && m_own_descriptor) {
     if (::close(m_descriptor) != 0)
       error.SetErrorToErrno();
@@ -181,7 +309,7 @@
   return error;
 }
 
-FILE *File::TakeStreamAndClear() {
+FILE *NativeFile::TakeStreamAndClear() {
   FILE *stream = GetStream();
   m_stream = NULL;
   m_descriptor = kInvalidDescriptor;
@@ -193,7 +321,7 @@
   return stream;
 }
 
-Status File::GetFileSpec(FileSpec &file_spec) const {
+Status NativeFile::GetFileSpec(FileSpec &file_spec) const {
   Status error;
 #ifdef F_GETPATH
   if (IsValid()) {
@@ -220,7 +348,8 @@
     }
   }
 #else
-  error.SetErrorString("File::GetFileSpec is not supported on this platform");
+  error.SetErrorString(
+      "NativeFile::GetFileSpec is not supported on this platform");
 #endif
 
   if (error.Fail())
@@ -228,7 +357,7 @@
   return error;
 }
 
-off_t File::SeekFromStart(off_t offset, Status *error_ptr) {
+off_t NativeFile::SeekFromStart(off_t offset, Status *error_ptr) {
   off_t result = 0;
   if (DescriptorIsValid()) {
     result = ::lseek(m_descriptor, offset, SEEK_SET);
@@ -254,7 +383,7 @@
   return result;
 }
 
-off_t File::SeekFromCurrent(off_t offset, Status *error_ptr) {
+off_t NativeFile::SeekFromCurrent(off_t offset, Status *error_ptr) {
   off_t result = -1;
   if (DescriptorIsValid()) {
     result = ::lseek(m_descriptor, offset, SEEK_CUR);
@@ -280,7 +409,7 @@
   return result;
 }
 
-off_t File::SeekFromEnd(off_t offset, Status *error_ptr) {
+off_t NativeFile::SeekFromEnd(off_t offset, Status *error_ptr) {
   off_t result = -1;
   if (DescriptorIsValid()) {
     result = ::lseek(m_descriptor, offset, SEEK_END);
@@ -306,7 +435,7 @@
   return result;
 }
 
-Status File::Flush() {
+Status NativeFile::Flush() {
   Status error;
   if (StreamIsValid()) {
     if (llvm::sys::RetryAfterSignal(EOF, ::fflush, m_stream) == EOF)
@@ -317,7 +446,7 @@
   return error;
 }
 
-Status File::Sync() {
+Status NativeFile::Sync() {
   Status error;
   if (DescriptorIsValid()) {
 #ifdef _WIN32
@@ -340,7 +469,7 @@
 #define MAX_WRITE_SIZE INT_MAX
 #endif
 
-Status File::Read(void *buf, size_t &num_bytes) {
+Status NativeFile::Read(void *buf, size_t &num_bytes) {
   Status error;
 
 #if defined(MAX_READ_SIZE)
@@ -399,7 +528,7 @@
   return error;
 }
 
-Status File::Write(const void *buf, size_t &num_bytes) {
+Status NativeFile::Write(const void *buf, size_t &num_bytes) {
   Status error;
 
 #if defined(MAX_WRITE_SIZE)
@@ -461,7 +590,7 @@
   return error;
 }
 
-Status File::Read(void *buf, size_t &num_bytes, off_t &offset) {
+Status NativeFile::Read(void *buf, size_t &num_bytes, off_t &offset) {
   Status error;
 
 #if defined(MAX_READ_SIZE)
@@ -521,7 +650,7 @@
   return error;
 }
 
-Status File::Write(const void *buf, size_t &num_bytes, off_t &offset) {
+Status NativeFile::Write(const void *buf, size_t &num_bytes, off_t &offset) {
   Status error;
 
 #if defined(MAX_WRITE_SIZE)
@@ -585,33 +714,12 @@
   return error;
 }
 
-// Print some formatted output to the stream.
-size_t File::Printf(const char *format, ...) {
-  va_list args;
-  va_start(args, format);
-  size_t result = PrintfVarArg(format, args);
-  va_end(args);
-  return result;
-}
-
-// Print some formatted output to the stream.
-size_t File::PrintfVarArg(const char *format, va_list args) {
-  size_t result = 0;
-  if (DescriptorIsValid()) {
-    char *s = nullptr;
-    result = vasprintf(&s, format, args);
-    if (s != nullptr) {
-      if (result > 0) {
-        size_t s_len = result;
-        Write(s, s_len);
-        result = s_len;
-      }
-      free(s);
-    }
-  } else if (StreamIsValid()) {
-    result = ::vfprintf(m_stream, format, args);
+size_t NativeFile::PrintfVarArg(const char *format, va_list args) {
+  if (StreamIsValid()) {
+    return ::vfprintf(m_stream, format, args);
+  } else {
+    return File::PrintfVarArg(format, args);
   }
-  return result;
 }
 
 mode_t File::ConvertOpenOptionsForPOSIXOpen(uint32_t open_options) {
@@ -638,49 +746,3 @@
   return mode;
 }
 
-void File::CalculateInteractiveAndTerminal() {
-  const int fd = GetDescriptor();
-  if (fd >= 0) {
-    m_is_interactive = eLazyBoolNo;
-    m_is_real_terminal = eLazyBoolNo;
-#if defined(_WIN32)
-    if (_isatty(fd)) {
-      m_is_interactive = eLazyBoolYes;
-      m_is_real_terminal = eLazyBoolYes;
-#if defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
-      m_supports_colors = eLazyBoolYes;
-#endif
-    }
-#else
-    if (isatty(fd)) {
-      m_is_interactive = eLazyBoolYes;
-      struct winsize window_size;
-      if (::ioctl(fd, TIOCGWINSZ, &window_size) == 0) {
-        if (window_size.ws_col > 0) {
-          m_is_real_terminal = eLazyBoolYes;
-          if (llvm::sys::Process::FileDescriptorHasColors(fd))
-            m_supports_colors = eLazyBoolYes;
-        }
-      }
-    }
-#endif
-  }
-}
-
-bool File::GetIsInteractive() {
-  if (m_is_interactive == eLazyBoolCalculate)
-    CalculateInteractiveAndTerminal();
-  return m_is_interactive == eLazyBoolYes;
-}
-
-bool File::GetIsRealTerminal() {
-  if (m_is_real_terminal == eLazyBoolCalculate)
-    CalculateInteractiveAndTerminal();
-  return m_is_real_terminal == eLazyBoolYes;
-}
-
-bool File::GetIsTerminalWithColors() {
-  if (m_supports_colors == eLazyBoolCalculate)
-    CalculateInteractiveAndTerminal();
-  return m_supports_colors == eLazyBoolYes;
-}
Index: lldb/trunk/source/Host/common/FileSystem.cpp
===================================================================
--- lldb/trunk/source/Host/common/FileSystem.cpp
+++ lldb/trunk/source/Host/common/FileSystem.cpp
@@ -435,7 +435,8 @@
     return llvm::errorCodeToError(
         std::error_code(errno, std::system_category()));
 
-  auto file = std::make_unique<File>(descriptor, options, should_close_fd);
+  auto file = std::unique_ptr<File>(
+      new NativeFile(descriptor, options, should_close_fd));
   assert(file->IsValid());
   return std::move(file);
 }
Index: lldb/trunk/source/Host/posix/ConnectionFileDescriptorPosix.cpp
===================================================================
--- lldb/trunk/source/Host/posix/ConnectionFileDescriptorPosix.cpp
+++ lldb/trunk/source/Host/posix/ConnectionFileDescriptorPosix.cpp
@@ -86,8 +86,8 @@
 ConnectionFileDescriptor::ConnectionFileDescriptor(int fd, bool owns_fd)
     : Connection(), m_pipe(), m_mutex(), m_shutting_down(false),
       m_waiting_for_accept(false), m_child_processes_inherit(false) {
-  m_write_sp = std::make_shared<File>(fd, File::eOpenOptionWrite, owns_fd);
-  m_read_sp = std::make_shared<File>(fd, File::eOpenOptionRead, false);
+  m_write_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionWrite, owns_fd);
+  m_read_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionRead, false);
 
   Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION |
                                                   LIBLLDB_LOG_OBJECT));
@@ -219,9 +219,9 @@
             m_write_sp = m_read_sp;
           } else {
             m_read_sp =
-                std::make_shared<File>(fd, File::eOpenOptionRead, false);
+                std::make_shared<NativeFile>(fd, File::eOpenOptionRead, false);
             m_write_sp =
-                std::make_shared<File>(fd, File::eOpenOptionWrite, false);
+                std::make_shared<NativeFile>(fd, File::eOpenOptionWrite, false);
           }
           m_uri = *addr;
           return eConnectionStatusSuccess;
@@ -270,8 +270,8 @@
           ::fcntl(fd, F_SETFL, flags);
         }
       }
-      m_read_sp = std::make_shared<File>(fd, File::eOpenOptionRead, true);
-      m_write_sp = std::make_shared<File>(fd, File::eOpenOptionWrite, false);
+      m_read_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionRead, true);
+      m_write_sp = std::make_shared<NativeFile>(fd, File::eOpenOptionWrite, false);
       return eConnectionStatusSuccess;
     }
 #endif
Index: lldb/trunk/scripts/Python/python-typemaps.swig
===================================================================
--- lldb/trunk/scripts/Python/python-typemaps.swig
+++ lldb/trunk/scripts/Python/python-typemaps.swig
@@ -422,7 +422,7 @@
     }
 %#endif
    using namespace lldb_private;
-   File file($1, false);
+   NativeFile file($1, false);
    PythonFile py_file(file, mode);
    $result = py_file.release();
    if (!$result)
Index: lldb/trunk/include/lldb/Host/File.h
===================================================================
--- lldb/trunk/include/lldb/Host/File.h
+++ lldb/trunk/include/lldb/Host/File.h
@@ -22,10 +22,12 @@
 namespace lldb_private {
 
 /// \class File File.h "lldb/Host/File.h"
-/// A file class.
+/// An abstract base class for files.
 ///
-/// A file class that divides abstracts the LLDB core from host file
-/// functionality.
+/// Files will often be NativeFiles, which provides a wrapper
+/// around host OS file functionality.   But it
+/// is also possible to subclass file to provide objects that have file
+/// or stream functionality but are not backed by any host OS file.
 class File : public IOObject {
 public:
   static int kInvalidDescriptor;
@@ -49,77 +51,80 @@
   };
 
   static mode_t ConvertOpenOptionsForPOSIXOpen(uint32_t open_options);
+  static uint32_t GetOptionsFromMode(llvm::StringRef mode);
+  static bool DescriptorIsValid(int descriptor) { return descriptor >= 0; };
 
   File()
-      : IOObject(eFDTypeFile), m_descriptor(kInvalidDescriptor),
-        m_own_descriptor(false), m_stream(kInvalidStream), m_options(0),
-        m_own_stream(false), m_is_interactive(eLazyBoolCalculate),
-        m_is_real_terminal(eLazyBoolCalculate),
-        m_supports_colors(eLazyBoolCalculate) {}
-
-  File(FILE *fh, bool transfer_ownership)
-      : IOObject(eFDTypeFile), m_descriptor(kInvalidDescriptor),
-        m_own_descriptor(false), m_stream(fh), m_options(0),
-        m_own_stream(transfer_ownership), m_is_interactive(eLazyBoolCalculate),
+      : IOObject(eFDTypeFile), m_is_interactive(eLazyBoolCalculate),
         m_is_real_terminal(eLazyBoolCalculate),
-        m_supports_colors(eLazyBoolCalculate) {}
+        m_supports_colors(eLazyBoolCalculate){};
 
-  File(int fd, uint32_t options, bool transfer_ownership)
-      : IOObject(eFDTypeFile), m_descriptor(fd),
-        m_own_descriptor(transfer_ownership), m_stream(kInvalidStream),
-        m_options(options), m_own_stream(false),
-        m_is_interactive(eLazyBoolCalculate),
-        m_is_real_terminal(eLazyBoolCalculate) {}
-
-  /// Destructor.
+  /// Read bytes from a file from the current file position into buf.
   ///
-  /// The destructor is virtual in case this class is subclassed.
-  ~File() override;
-
-  bool IsValid() const override {
-    return DescriptorIsValid() || StreamIsValid();
-  }
-
-  /// Convert to pointer operator.
+  /// NOTE: This function is NOT thread safe. Use the read function
+  /// that takes an "off_t &offset" to ensure correct operation in multi-
+  /// threaded environments.
   ///
-  /// This allows code to check a File object to see if it contains anything
-  /// valid using code such as:
+  /// \param[out] buf
   ///
-  /// \code
-  /// File file(...);
-  /// if (file)
-  /// { ...
-  /// \endcode
+  /// \param[in,out] num_bytes.
+  ///    Pass in the size of buf.  Read will pass out the number
+  ///    of bytes read.   Zero bytes read with no error indicates
+  ///    EOF.
   ///
   /// \return
-  ///     A pointer to this object if either the directory or filename
-  ///     is valid, nullptr otherwise.
-  operator bool() const { return DescriptorIsValid() || StreamIsValid(); }
+  ///    success, ENOTSUP, or another error.
+  Status Read(void *buf, size_t &num_bytes) override;
 
-  /// Logical NOT operator.
+  /// Write bytes from buf to a file at the current file position.
+  ///
+  /// NOTE: This function is NOT thread safe. Use the write function
+  /// that takes an "off_t &offset" to ensure correct operation in multi-
+  /// threaded environments.
   ///
-  /// This allows code to check a File object to see if it is invalid using
-  /// code such as:
+  /// \param[in] buf
   ///
-  /// \code
-  /// File file(...);
-  /// if (!file)
-  /// { ...
-  /// \endcode
+  /// \param[in,out] num_bytes
+  ///    Pass in the size of buf.  Write will pass out the number
+  ///    of bytes written.   Write will attempt write the full number
+  ///    of bytes and will not return early except on error.
   ///
   /// \return
-  ///     Returns \b true if the object has an empty directory and
-  ///     filename, \b false otherwise.
-  bool operator!() const { return !DescriptorIsValid() && !StreamIsValid(); }
+  ///    success, ENOTSUP, or another error.
+  Status Write(const void *buf, size_t &num_bytes) override;
 
-  /// Get the file spec for this file.
+  /// IsValid
   ///
   /// \return
-  ///     A reference to the file specification object.
-  Status GetFileSpec(FileSpec &file_spec) const;
+  ///    true iff the file is valid.
+  bool IsValid() const override;
 
+  /// Flush any buffers and release any resources owned by the file.
+  /// After Close() the file will be invalid.
+  ///
+  /// \return
+  ///     success or an error.
   Status Close() override;
 
+  /// Get a handle that can be used for OS polling interfaces, such
+  /// as WaitForMultipleObjects, select, or epoll.   This may return
+  /// IOObject::kInvalidHandleValue if none is available.   This will
+  /// generally be the same as the file descriptor, this function
+  /// is not interchangeable with GetDescriptor().   A WaitableHandle
+  /// must only be used for polling, not actual I/O.
+  ///
+  /// \return
+  ///     a valid handle or IOObject::kInvalidHandleValue
+  WaitableHandle GetWaitableHandle() override;
+
+  /// Get the file specification for this file, if possible.
+  ///
+  /// \param[out] file_spec
+  ///     the file specification.
+  /// \return
+  ///     ENOTSUP, success, or another error.
+  virtual Status GetFileSpec(FileSpec &file_spec) const;
+
   /// DEPRECATED! Extract the underlying FILE* and reset this File without closing it.
   ///
   /// This is only here to support legacy SB interfaces that need to convert scripting
@@ -132,52 +137,26 @@
   /// \return
   ///     The underlying FILE* stream from this File, if one exists and can be extracted,
   ///     nullptr otherwise.
-  FILE *TakeStreamAndClear();
-
-  int GetDescriptor() const;
-
-  static uint32_t GetOptionsFromMode(llvm::StringRef mode);
-
-  WaitableHandle GetWaitableHandle() override;
-
-  FILE *GetStream();
+  virtual FILE *TakeStreamAndClear();
 
-  /// Read bytes from a file from the current file position.
-  ///
-  /// NOTE: This function is NOT thread safe. Use the read function
-  /// that takes an "off_t &offset" to ensure correct operation in multi-
-  /// threaded environments.
-  ///
-  /// \param[in] buf
-  ///     A buffer where to put the bytes that are read.
-  ///
-  /// \param[in,out] num_bytes
-  ///     The number of bytes to read form the current file position
-  ///     which gets modified with the number of bytes that were read.
+  /// Get underlying OS file descriptor for this file, or kInvalidDescriptor.
+  /// If the descriptor is valid, then it may be used directly for I/O
+  /// However, the File may also perform it's own buffering, so avoid using
+  /// this if it is not necessary, or use Flush() appropriately.
   ///
   /// \return
-  ///     An error object that indicates success or the reason for
-  ///     failure.
-  Status Read(void *buf, size_t &num_bytes) override;
+  ///    a valid file descriptor for this file or kInvalidDescriptor
+  virtual int GetDescriptor() const;
 
-  /// Write bytes to a file at the current file position.
-  ///
-  /// NOTE: This function is NOT thread safe. Use the write function
-  /// that takes an "off_t &offset" to ensure correct operation in multi-
-  /// threaded environments.
-  ///
-  /// \param[in] buf
-  ///     A buffer where to put the bytes that are read.
+  /// Get the underlying libc stream for this file, or NULL.
   ///
-  /// \param[in,out] num_bytes
-  ///     The number of bytes to write to the current file position
-  ///     which gets modified with the number of bytes that were
-  ///     written.
+  /// Not all valid files will have a FILE* stream.   This should only be
+  /// used if absolutely necessary, such as to interact with 3rd party
+  /// libraries that need FILE* streams.
   ///
   /// \return
-  ///     An error object that indicates success or the reason for
-  ///     failure.
-  Status Write(const void *buf, size_t &num_bytes) override;
+  ///    a valid stream or NULL;
+  virtual FILE *GetStream();
 
   /// Seek to an offset relative to the beginning of the file.
   ///
@@ -197,7 +176,7 @@
   ///
   /// \return
   ///     The resulting seek offset, or -1 on error.
-  off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr);
+  virtual off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr);
 
   /// Seek to an offset relative to the current file position.
   ///
@@ -217,7 +196,7 @@
   ///
   /// \return
   ///     The resulting seek offset, or -1 on error.
-  off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr);
+  virtual off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr);
 
   /// Seek to an offset relative to the end of the file.
   ///
@@ -238,7 +217,7 @@
   ///
   /// \return
   ///     The resulting seek offset, or -1 on error.
-  off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr);
+  virtual off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr);
 
   /// Read bytes from a file from the specified file offset.
   ///
@@ -261,7 +240,7 @@
   /// \return
   ///     An error object that indicates success or the reason for
   ///     failure.
-  Status Read(void *dst, size_t &num_bytes, off_t &offset);
+  virtual Status Read(void *dst, size_t &num_bytes, off_t &offset);
 
   /// Write bytes to a file at the specified file offset.
   ///
@@ -286,21 +265,48 @@
   /// \return
   ///     An error object that indicates success or the reason for
   ///     failure.
-  Status Write(const void *src, size_t &num_bytes, off_t &offset);
+  virtual Status Write(const void *src, size_t &num_bytes, off_t &offset);
 
   /// Flush the current stream
   ///
   /// \return
   ///     An error object that indicates success or the reason for
   ///     failure.
-  Status Flush();
+  virtual Status Flush();
 
   /// Sync to disk.
   ///
   /// \return
   ///     An error object that indicates success or the reason for
   ///     failure.
-  Status Sync();
+  virtual Status Sync();
+
+  /// Output printf formatted output to the stream.
+  ///
+  /// NOTE: this is not virtual, because it just calls the va_list
+  /// version of the function.
+  ///
+  /// Print some formatted output to the stream.
+  ///
+  /// \param[in] format
+  ///     A printf style format string.
+  ///
+  /// \param[in] ...
+  ///     Variable arguments that are needed for the printf style
+  ///     format string \a format.
+  size_t Printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
+
+  /// Output printf formatted output to the stream.
+  ///
+  /// Print some formatted output to the stream.
+  ///
+  /// \param[in] format
+  ///     A printf style format string.
+  ///
+  /// \param[in] args
+  ///     Variable arguments that are needed for the printf style
+  ///     format string \a format.
+  virtual size_t PrintfVarArg(const char *format, va_list args);
 
   /// Get the permissions for a this file.
   ///
@@ -327,44 +333,80 @@
   ///     a non-zero width and height, false otherwise.
   bool GetIsRealTerminal();
 
-  bool GetIsTerminalWithColors();
-
-  /// Output printf formatted output to the stream.
-  ///
-  /// Print some formatted output to the stream.
-  ///
-  /// \param[in] format
-  ///     A printf style format string.
+  /// Return true if this file is a terminal which supports colors.
   ///
-  /// \param[in] ...
-  ///     Variable arguments that are needed for the printf style
-  ///     format string \a format.
-  size_t Printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
+  /// \return
+  ///    True iff this is a terminal and it supports colors.
+  bool GetIsTerminalWithColors();
 
-  size_t PrintfVarArg(const char *format, va_list args);
+  operator bool() const { return IsValid(); };
 
-  static bool DescriptorIsValid(int descriptor) { return descriptor >= 0; };
+  bool operator!() const { return !IsValid(); };
 
 protected:
-  bool DescriptorIsValid() const { return DescriptorIsValid(m_descriptor); }
-
-  bool StreamIsValid() const { return m_stream != kInvalidStream; }
+  LazyBool m_is_interactive;
+  LazyBool m_is_real_terminal;
+  LazyBool m_supports_colors;
 
   void CalculateInteractiveAndTerminal();
 
+private:
+  DISALLOW_COPY_AND_ASSIGN(File);
+};
+
+class NativeFile : public File {
+public:
+  NativeFile()
+      : m_descriptor(kInvalidDescriptor), m_own_descriptor(false),
+        m_stream(kInvalidStream), m_options(0), m_own_stream(false) {}
+
+  NativeFile(FILE *fh, bool transfer_ownership)
+      : m_descriptor(kInvalidDescriptor), m_own_descriptor(false), m_stream(fh),
+        m_options(0), m_own_stream(transfer_ownership) {}
+
+  NativeFile(int fd, uint32_t options, bool transfer_ownership)
+      : m_descriptor(fd), m_own_descriptor(transfer_ownership),
+        m_stream(kInvalidStream), m_options(options), m_own_stream(false) {}
+
+  ~NativeFile() override { Close(); }
+
+  bool IsValid() const override {
+    return DescriptorIsValid() || StreamIsValid();
+  }
+
+  Status Read(void *buf, size_t &num_bytes) override;
+  Status Write(const void *buf, size_t &num_bytes) override;
+  Status Close() override;
+  WaitableHandle GetWaitableHandle() override;
+  Status GetFileSpec(FileSpec &file_spec) const override;
+  FILE *TakeStreamAndClear() override;
+  int GetDescriptor() const override;
+  FILE *GetStream() override;
+  off_t SeekFromStart(off_t offset, Status *error_ptr = nullptr) override;
+  off_t SeekFromCurrent(off_t offset, Status *error_ptr = nullptr) override;
+  off_t SeekFromEnd(off_t offset, Status *error_ptr = nullptr) override;
+  Status Read(void *dst, size_t &num_bytes, off_t &offset) override;
+  Status Write(const void *src, size_t &num_bytes, off_t &offset) override;
+  Status Flush() override;
+  Status Sync() override;
+  size_t PrintfVarArg(const char *format, va_list args) override;
+
+protected:
+  bool DescriptorIsValid() const {
+    return File::DescriptorIsValid(m_descriptor);
+  }
+  bool StreamIsValid() const { return m_stream != kInvalidStream; }
+
   // Member variables
   int m_descriptor;
   bool m_own_descriptor;
   FILE *m_stream;
   uint32_t m_options;
   bool m_own_stream;
-  LazyBool m_is_interactive;
-  LazyBool m_is_real_terminal;
-  LazyBool m_supports_colors;
   std::mutex offset_access_mutex;
 
 private:
-  DISALLOW_COPY_AND_ASSIGN(File);
+  DISALLOW_COPY_AND_ASSIGN(NativeFile);
 };
 
 } // namespace lldb_private
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to