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