1 //===-- SBStream.cpp ----------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/API/SBStream.h" 11 12 #include "lldb/Core/Error.h" 13 #include "lldb/Core/Stream.h" 14 #include "lldb/Core/StreamFile.h" 15 #include "lldb/Core/StreamString.h" 16 17 using namespace lldb; 18 using namespace lldb_private; 19 20 SBStream::SBStream() : m_opaque_ap(new StreamString()), m_is_file(false) {} 21 22 SBStream::SBStream(SBStream &&rhs) 23 : m_opaque_ap(std::move(rhs.m_opaque_ap)), m_is_file(rhs.m_is_file) {} 24 25 SBStream::~SBStream() {} 26 27 bool SBStream::IsValid() const { return (m_opaque_ap.get() != NULL); } 28 29 // If this stream is not redirected to a file, it will maintain a local 30 // cache for the stream data which can be accessed using this accessor. 31 const char *SBStream::GetData() { 32 if (m_is_file || m_opaque_ap.get() == NULL) 33 return NULL; 34 35 return static_cast<StreamString *>(m_opaque_ap.get())->GetData(); 36 } 37 38 // If this stream is not redirected to a file, it will maintain a local 39 // cache for the stream output whose length can be accessed using this 40 // accessor. 41 size_t SBStream::GetSize() { 42 if (m_is_file || m_opaque_ap.get() == NULL) 43 return 0; 44 45 return static_cast<StreamString *>(m_opaque_ap.get())->GetSize(); 46 } 47 48 void SBStream::Printf(const char *format, ...) { 49 if (!format) 50 return; 51 va_list args; 52 va_start(args, format); 53 ref().PrintfVarArg(format, args); 54 va_end(args); 55 } 56 57 void SBStream::RedirectToFile(const char *path, bool append) { 58 if (path == nullptr) 59 return; 60 61 std::string local_data; 62 if (m_opaque_ap.get()) { 63 // See if we have any locally backed data. If so, copy it so we can then 64 // redirect it to the file so we don't lose the data 65 if (!m_is_file) 66 local_data.swap( 67 static_cast<StreamString *>(m_opaque_ap.get())->GetString()); 68 } 69 StreamFile *stream_file = new StreamFile; 70 uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; 71 if (append) 72 open_options |= File::eOpenOptionAppend; 73 else 74 open_options |= File::eOpenOptionTruncate; 75 stream_file->GetFile().Open(path, open_options, 76 lldb::eFilePermissionsFileDefault); 77 78 m_opaque_ap.reset(stream_file); 79 80 if (m_opaque_ap.get()) { 81 m_is_file = true; 82 83 // If we had any data locally in our StreamString, then pass that along to 84 // the to new file we are redirecting to. 85 if (!local_data.empty()) 86 m_opaque_ap->Write(&local_data[0], local_data.size()); 87 } else 88 m_is_file = false; 89 } 90 91 void SBStream::RedirectToFileHandle(FILE *fh, bool transfer_fh_ownership) { 92 if (fh == nullptr) 93 return; 94 95 std::string local_data; 96 if (m_opaque_ap.get()) { 97 // See if we have any locally backed data. If so, copy it so we can then 98 // redirect it to the file so we don't lose the data 99 if (!m_is_file) 100 local_data.swap( 101 static_cast<StreamString *>(m_opaque_ap.get())->GetString()); 102 } 103 m_opaque_ap.reset(new StreamFile(fh, transfer_fh_ownership)); 104 105 if (m_opaque_ap.get()) { 106 m_is_file = true; 107 108 // If we had any data locally in our StreamString, then pass that along to 109 // the to new file we are redirecting to. 110 if (!local_data.empty()) 111 m_opaque_ap->Write(&local_data[0], local_data.size()); 112 } else 113 m_is_file = false; 114 } 115 116 void SBStream::RedirectToFileDescriptor(int fd, bool transfer_fh_ownership) { 117 std::string local_data; 118 if (m_opaque_ap.get()) { 119 // See if we have any locally backed data. If so, copy it so we can then 120 // redirect it to the file so we don't lose the data 121 if (!m_is_file) 122 local_data.swap( 123 static_cast<StreamString *>(m_opaque_ap.get())->GetString()); 124 } 125 126 m_opaque_ap.reset(new StreamFile(::fdopen(fd, "w"), transfer_fh_ownership)); 127 if (m_opaque_ap.get()) { 128 m_is_file = true; 129 130 // If we had any data locally in our StreamString, then pass that along to 131 // the to new file we are redirecting to. 132 if (!local_data.empty()) 133 m_opaque_ap->Write(&local_data[0], local_data.size()); 134 } else 135 m_is_file = false; 136 } 137 138 lldb_private::Stream *SBStream::operator->() { return m_opaque_ap.get(); } 139 140 lldb_private::Stream *SBStream::get() { return m_opaque_ap.get(); } 141 142 lldb_private::Stream &SBStream::ref() { 143 if (m_opaque_ap.get() == NULL) 144 m_opaque_ap.reset(new StreamString()); 145 return *m_opaque_ap.get(); 146 } 147 148 void SBStream::Clear() { 149 if (m_opaque_ap.get()) { 150 // See if we have any locally backed data. If so, copy it so we can then 151 // redirect it to the file so we don't lose the data 152 if (m_is_file) 153 m_opaque_ap.reset(); 154 else 155 static_cast<StreamString *>(m_opaque_ap.get())->GetString().clear(); 156 } 157 } 158