180814287SRaphael Isemann //===-- IOHandler.cpp -----------------------------------------------------===// 244d93782SGreg Clayton // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 644d93782SGreg Clayton // 744d93782SGreg Clayton //===----------------------------------------------------------------------===// 844d93782SGreg Clayton 92f3df613SZachary Turner #include "lldb/Core/IOHandler.h" 102f3df613SZachary Turner 117c9aa073STodd Fiala #if defined(__APPLE__) 127c9aa073STodd Fiala #include <deque> 137c9aa073STodd Fiala #endif 1444d93782SGreg Clayton #include <string> 1544d93782SGreg Clayton 1644d93782SGreg Clayton #include "lldb/Core/Debugger.h" 1744d93782SGreg Clayton #include "lldb/Core/StreamFile.h" 18babbd554SJonas Devlieghere #include "lldb/Host/Config.h" 19672d2c12SJonas Devlieghere #include "lldb/Host/File.h" 20672d2c12SJonas Devlieghere #include "lldb/Utility/Predicate.h" 21672d2c12SJonas Devlieghere #include "lldb/Utility/Status.h" 22672d2c12SJonas Devlieghere #include "lldb/Utility/StreamString.h" 23672d2c12SJonas Devlieghere #include "lldb/Utility/StringList.h" 24672d2c12SJonas Devlieghere #include "lldb/lldb-forward.h" 252f3df613SZachary Turner 2662456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 2744d93782SGreg Clayton #include "lldb/Host/Editline.h" 28cacde7dfSTodd Fiala #endif 2944d93782SGreg Clayton #include "lldb/Interpreter/CommandCompletions.h" 3044d93782SGreg Clayton #include "lldb/Interpreter/CommandInterpreter.h" 31672d2c12SJonas Devlieghere #include "llvm/ADT/StringRef.h" 322f3df613SZachary Turner 335c82608dSHaibo Huang #ifdef _WIN32 34aaea8ee6SZachary Turner #include "lldb/Host/windows/windows.h" 35fab31220STed Woodward #endif 36fab31220STed Woodward 37672d2c12SJonas Devlieghere #include <memory> 38672d2c12SJonas Devlieghere #include <mutex> 392f3df613SZachary Turner 40672d2c12SJonas Devlieghere #include <assert.h> 41672d2c12SJonas Devlieghere #include <ctype.h> 42672d2c12SJonas Devlieghere #include <errno.h> 43672d2c12SJonas Devlieghere #include <locale.h> 44672d2c12SJonas Devlieghere #include <stdint.h> 45672d2c12SJonas Devlieghere #include <stdio.h> 46672d2c12SJonas Devlieghere #include <string.h> 47672d2c12SJonas Devlieghere #include <type_traits> 482f3df613SZachary Turner 4944d93782SGreg Clayton using namespace lldb; 5044d93782SGreg Clayton using namespace lldb_private; 51b3faa01fSLawrence D'Anna using llvm::None; 52b3faa01fSLawrence D'Anna using llvm::Optional; 53b3faa01fSLawrence D'Anna using llvm::StringRef; 54b3faa01fSLawrence D'Anna 55b9c1b51eSKate Stone IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type) 56b9c1b51eSKate Stone : IOHandler(debugger, type, 577ca15ba7SLawrence D'Anna FileSP(), // Adopt STDIN from top input reader 5844d93782SGreg Clayton StreamFileSP(), // Adopt STDOUT from top input reader 59340b0309SGreg Clayton StreamFileSP(), // Adopt STDERR from top input reader 60d77c2e09SJonas Devlieghere 0, // Flags 61d77c2e09SJonas Devlieghere nullptr // Shadow file recorder 62d77c2e09SJonas Devlieghere ) {} 6344d93782SGreg Clayton 64b9c1b51eSKate Stone IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type, 657ca15ba7SLawrence D'Anna const lldb::FileSP &input_sp, 6644d93782SGreg Clayton const lldb::StreamFileSP &output_sp, 67d77c2e09SJonas Devlieghere const lldb::StreamFileSP &error_sp, uint32_t flags, 68d77c2e09SJonas Devlieghere repro::DataRecorder *data_recorder) 69b9c1b51eSKate Stone : m_debugger(debugger), m_input_sp(input_sp), m_output_sp(output_sp), 70d77c2e09SJonas Devlieghere m_error_sp(error_sp), m_data_recorder(data_recorder), m_popped(false), 71d77c2e09SJonas Devlieghere m_flags(flags), m_type(type), m_user_data(nullptr), m_done(false), 72d77c2e09SJonas Devlieghere m_active(false) { 7344d93782SGreg Clayton // If any files are not specified, then adopt them from the top input reader. 7444d93782SGreg Clayton if (!m_input_sp || !m_output_sp || !m_error_sp) 75b9c1b51eSKate Stone debugger.AdoptTopIOHandlerFilesIfInvalid(m_input_sp, m_output_sp, 7644d93782SGreg Clayton m_error_sp); 7744d93782SGreg Clayton } 7844d93782SGreg Clayton 79315b6884SEugene Zelenko IOHandler::~IOHandler() = default; 8044d93782SGreg Clayton 81b9c1b51eSKate Stone int IOHandler::GetInputFD() { 827ca15ba7SLawrence D'Anna return (m_input_sp ? m_input_sp->GetDescriptor() : -1); 8344d93782SGreg Clayton } 8444d93782SGreg Clayton 85b9c1b51eSKate Stone int IOHandler::GetOutputFD() { 86c5dac77aSEugene Zelenko return (m_output_sp ? m_output_sp->GetFile().GetDescriptor() : -1); 8744d93782SGreg Clayton } 8844d93782SGreg Clayton 89b9c1b51eSKate Stone int IOHandler::GetErrorFD() { 90c5dac77aSEugene Zelenko return (m_error_sp ? m_error_sp->GetFile().GetDescriptor() : -1); 9144d93782SGreg Clayton } 9244d93782SGreg Clayton 93b9c1b51eSKate Stone FILE *IOHandler::GetInputFILE() { 947ca15ba7SLawrence D'Anna return (m_input_sp ? m_input_sp->GetStream() : nullptr); 9544d93782SGreg Clayton } 9644d93782SGreg Clayton 97b9c1b51eSKate Stone FILE *IOHandler::GetOutputFILE() { 98c5dac77aSEugene Zelenko return (m_output_sp ? m_output_sp->GetFile().GetStream() : nullptr); 9944d93782SGreg Clayton } 10044d93782SGreg Clayton 101b9c1b51eSKate Stone FILE *IOHandler::GetErrorFILE() { 102c5dac77aSEugene Zelenko return (m_error_sp ? m_error_sp->GetFile().GetStream() : nullptr); 10344d93782SGreg Clayton } 10444d93782SGreg Clayton 1057ca15ba7SLawrence D'Anna FileSP &IOHandler::GetInputFileSP() { return m_input_sp; } 10644d93782SGreg Clayton 1077ca15ba7SLawrence D'Anna StreamFileSP &IOHandler::GetOutputStreamFileSP() { return m_output_sp; } 10844d93782SGreg Clayton 1097ca15ba7SLawrence D'Anna StreamFileSP &IOHandler::GetErrorStreamFileSP() { return m_error_sp; } 11044d93782SGreg Clayton 111b9c1b51eSKate Stone bool IOHandler::GetIsInteractive() { 1127ca15ba7SLawrence D'Anna return GetInputFileSP() ? GetInputFileSP()->GetIsInteractive() : false; 113340b0309SGreg Clayton } 114340b0309SGreg Clayton 115b9c1b51eSKate Stone bool IOHandler::GetIsRealTerminal() { 1167ca15ba7SLawrence D'Anna return GetInputFileSP() ? GetInputFileSP()->GetIsRealTerminal() : false; 117340b0309SGreg Clayton } 11844d93782SGreg Clayton 119b9c1b51eSKate Stone void IOHandler::SetPopped(bool b) { m_popped.SetValue(b, eBroadcastOnChange); } 120e30f11d9SKate Stone 121b9c1b51eSKate Stone void IOHandler::WaitForPop() { m_popped.WaitForValueEqualTo(true); } 122e30f11d9SKate Stone 123b9c1b51eSKate Stone void IOHandlerStack::PrintAsync(Stream *stream, const char *s, size_t len) { 124b9c1b51eSKate Stone if (stream) { 12516ff8604SSaleem Abdulrasool std::lock_guard<std::recursive_mutex> guard(m_mutex); 1264446487dSPavel Labath if (m_top) 1274446487dSPavel Labath m_top->PrintAsync(stream, s, len); 128*4deea652SPavel Labath else 129*4deea652SPavel Labath stream->Write(s, len); 1304446487dSPavel Labath } 1314446487dSPavel Labath } 1324446487dSPavel Labath 1337a120c8bSZachary Turner IOHandlerConfirm::IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt, 134b9c1b51eSKate Stone bool default_response) 135b9c1b51eSKate Stone : IOHandlerEditline( 136b9c1b51eSKate Stone debugger, IOHandler::Type::Confirm, 137c5dac77aSEugene Zelenko nullptr, // nullptr editline_name means no history loaded/saved 138514d8cd8SZachary Turner llvm::StringRef(), // No prompt 139514d8cd8SZachary Turner llvm::StringRef(), // No continuation prompt 14044d93782SGreg Clayton false, // Multi-line 141e30f11d9SKate Stone false, // Don't colorize the prompt (i.e. the confirm message.) 142d77c2e09SJonas Devlieghere 0, *this, nullptr), 143b9c1b51eSKate Stone m_default_response(default_response), m_user_response(default_response) { 14444d93782SGreg Clayton StreamString prompt_stream; 14544d93782SGreg Clayton prompt_stream.PutCString(prompt); 14644d93782SGreg Clayton if (m_default_response) 14744d93782SGreg Clayton prompt_stream.Printf(": [Y/n] "); 14844d93782SGreg Clayton else 14944d93782SGreg Clayton prompt_stream.Printf(": [y/N] "); 15044d93782SGreg Clayton 151514d8cd8SZachary Turner SetPrompt(prompt_stream.GetString()); 15244d93782SGreg Clayton } 15344d93782SGreg Clayton 154315b6884SEugene Zelenko IOHandlerConfirm::~IOHandlerConfirm() = default; 15544d93782SGreg Clayton 156ae34ed2cSRaphael Isemann void IOHandlerConfirm::IOHandlerComplete(IOHandler &io_handler, 1572fc20f65SRaphael Isemann CompletionRequest &request) { 1581153dc96SRaphael Isemann if (request.GetRawCursorPos() != 0) 1591153dc96SRaphael Isemann return; 1601153dc96SRaphael Isemann request.AddCompletion(m_default_response ? "y" : "n"); 16144d93782SGreg Clayton } 16244d93782SGreg Clayton 163b9c1b51eSKate Stone void IOHandlerConfirm::IOHandlerInputComplete(IOHandler &io_handler, 164b9c1b51eSKate Stone std::string &line) { 165b9c1b51eSKate Stone if (line.empty()) { 16644d93782SGreg Clayton // User just hit enter, set the response to the default 16744d93782SGreg Clayton m_user_response = m_default_response; 16844d93782SGreg Clayton io_handler.SetIsDone(true); 16944d93782SGreg Clayton return; 17044d93782SGreg Clayton } 17144d93782SGreg Clayton 172b9c1b51eSKate Stone if (line.size() == 1) { 173b9c1b51eSKate Stone switch (line[0]) { 17444d93782SGreg Clayton case 'y': 17544d93782SGreg Clayton case 'Y': 17644d93782SGreg Clayton m_user_response = true; 17744d93782SGreg Clayton io_handler.SetIsDone(true); 17844d93782SGreg Clayton return; 17944d93782SGreg Clayton case 'n': 18044d93782SGreg Clayton case 'N': 18144d93782SGreg Clayton m_user_response = false; 18244d93782SGreg Clayton io_handler.SetIsDone(true); 18344d93782SGreg Clayton return; 18444d93782SGreg Clayton default: 18544d93782SGreg Clayton break; 18644d93782SGreg Clayton } 18744d93782SGreg Clayton } 18844d93782SGreg Clayton 189b9c1b51eSKate Stone if (line == "yes" || line == "YES" || line == "Yes") { 19044d93782SGreg Clayton m_user_response = true; 19144d93782SGreg Clayton io_handler.SetIsDone(true); 192b9c1b51eSKate Stone } else if (line == "no" || line == "NO" || line == "No") { 19344d93782SGreg Clayton m_user_response = false; 19444d93782SGreg Clayton io_handler.SetIsDone(true); 19544d93782SGreg Clayton } 19644d93782SGreg Clayton } 19744d93782SGreg Clayton 198ae34ed2cSRaphael Isemann void IOHandlerDelegate::IOHandlerComplete(IOHandler &io_handler, 1992fc20f65SRaphael Isemann CompletionRequest &request) { 200b9c1b51eSKate Stone switch (m_completion) { 20144d93782SGreg Clayton case Completion::None: 20244d93782SGreg Clayton break; 20344d93782SGreg Clayton case Completion::LLDBCommand: 204ae34ed2cSRaphael Isemann io_handler.GetDebugger().GetCommandInterpreter().HandleCompletion(request); 205ae34ed2cSRaphael Isemann break; 206ae34ed2cSRaphael Isemann case Completion::Expression: 207b9c1b51eSKate Stone CommandCompletions::InvokeCommonCompletionCallbacks( 208b9c1b51eSKate Stone io_handler.GetDebugger().GetCommandInterpreter(), 209ae34ed2cSRaphael Isemann CommandCompletions::eVariablePathCompletion, request, nullptr); 210ae34ed2cSRaphael Isemann break; 21144d93782SGreg Clayton } 21244d93782SGreg Clayton } 21344d93782SGreg Clayton 214b9c1b51eSKate Stone IOHandlerEditline::IOHandlerEditline( 215b9c1b51eSKate Stone Debugger &debugger, IOHandler::Type type, 21644d93782SGreg Clayton const char *editline_name, // Used for saving history files 217514d8cd8SZachary Turner llvm::StringRef prompt, llvm::StringRef continuation_prompt, 218514d8cd8SZachary Turner bool multi_line, bool color_prompts, uint32_t line_number_start, 219d77c2e09SJonas Devlieghere IOHandlerDelegate &delegate, repro::DataRecorder *data_recorder) 220b9c1b51eSKate Stone : IOHandlerEditline(debugger, type, 2217ca15ba7SLawrence D'Anna FileSP(), // Inherit input from top input reader 22244d93782SGreg Clayton StreamFileSP(), // Inherit output from top input reader 22344d93782SGreg Clayton StreamFileSP(), // Inherit error from top input reader 224340b0309SGreg Clayton 0, // Flags 22544d93782SGreg Clayton editline_name, // Used for saving history files 226b9c1b51eSKate Stone prompt, continuation_prompt, multi_line, color_prompts, 227d77c2e09SJonas Devlieghere line_number_start, delegate, data_recorder) {} 22844d93782SGreg Clayton 229b9c1b51eSKate Stone IOHandlerEditline::IOHandlerEditline( 2307ca15ba7SLawrence D'Anna Debugger &debugger, IOHandler::Type type, const lldb::FileSP &input_sp, 2317ca15ba7SLawrence D'Anna const lldb::StreamFileSP &output_sp, const lldb::StreamFileSP &error_sp, 2327ca15ba7SLawrence D'Anna uint32_t flags, 23344d93782SGreg Clayton const char *editline_name, // Used for saving history files 234514d8cd8SZachary Turner llvm::StringRef prompt, llvm::StringRef continuation_prompt, 235514d8cd8SZachary Turner bool multi_line, bool color_prompts, uint32_t line_number_start, 236d77c2e09SJonas Devlieghere IOHandlerDelegate &delegate, repro::DataRecorder *data_recorder) 237d77c2e09SJonas Devlieghere : IOHandler(debugger, type, input_sp, output_sp, error_sp, flags, 238d77c2e09SJonas Devlieghere data_recorder), 23962456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 240d5b44036SJonas Devlieghere m_editline_up(), 241cacde7dfSTodd Fiala #endif 242b9c1b51eSKate Stone m_delegate(delegate), m_prompt(), m_continuation_prompt(), 243b9c1b51eSKate Stone m_current_lines_ptr(nullptr), m_base_line_number(line_number_start), 244b9c1b51eSKate Stone m_curr_line_idx(UINT32_MAX), m_multi_line(multi_line), 245b9c1b51eSKate Stone m_color_prompts(color_prompts), m_interrupt_exits(true), 246b9c1b51eSKate Stone m_editing(false) { 24744d93782SGreg Clayton SetPrompt(prompt); 24844d93782SGreg Clayton 24962456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 250914b8d98SDeepak Panickal bool use_editline = false; 251340b0309SGreg Clayton 252609010d0SLawrence D'Anna use_editline = GetInputFILE() && GetOutputFILE() && GetErrorFILE() && 253609010d0SLawrence D'Anna m_input_sp && m_input_sp->GetIsRealTerminal(); 25444d93782SGreg Clayton 255b9c1b51eSKate Stone if (use_editline) { 256d5b44036SJonas Devlieghere m_editline_up.reset(new Editline(editline_name, GetInputFILE(), 257b9c1b51eSKate Stone GetOutputFILE(), GetErrorFILE(), 258e30f11d9SKate Stone m_color_prompts)); 259d5b44036SJonas Devlieghere m_editline_up->SetIsInputCompleteCallback(IsInputCompleteCallback, this); 260d5b44036SJonas Devlieghere m_editline_up->SetAutoCompleteCallback(AutoCompleteCallback, this); 261e30f11d9SKate Stone // See if the delegate supports fixing indentation 262e30f11d9SKate Stone const char *indent_chars = delegate.IOHandlerGetFixIndentationCharacters(); 263b9c1b51eSKate Stone if (indent_chars) { 264b9c1b51eSKate Stone // The delegate does support indentation, hook it up so when any 26505097246SAdrian Prantl // indentation character is typed, the delegate gets a chance to fix it 266d5b44036SJonas Devlieghere m_editline_up->SetFixIndentationCallback(FixIndentationCallback, this, 267b9c1b51eSKate Stone indent_chars); 268e30f11d9SKate Stone } 26944d93782SGreg Clayton } 270cacde7dfSTodd Fiala #endif 271e30f11d9SKate Stone SetBaseLineNumber(m_base_line_number); 272514d8cd8SZachary Turner SetPrompt(prompt); 273e30f11d9SKate Stone SetContinuationPrompt(continuation_prompt); 27444d93782SGreg Clayton } 27544d93782SGreg Clayton 276b9c1b51eSKate Stone IOHandlerEditline::~IOHandlerEditline() { 27762456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 278d5b44036SJonas Devlieghere m_editline_up.reset(); 279cacde7dfSTodd Fiala #endif 28044d93782SGreg Clayton } 28144d93782SGreg Clayton 282b9c1b51eSKate Stone void IOHandlerEditline::Activate() { 283e30f11d9SKate Stone IOHandler::Activate(); 2840affb582SDave Lee m_delegate.IOHandlerActivated(*this, GetIsInteractive()); 285e30f11d9SKate Stone } 286e30f11d9SKate Stone 287b9c1b51eSKate Stone void IOHandlerEditline::Deactivate() { 288e30f11d9SKate Stone IOHandler::Deactivate(); 289e30f11d9SKate Stone m_delegate.IOHandlerDeactivated(*this); 290e30f11d9SKate Stone } 291e30f11d9SKate Stone 292b3faa01fSLawrence D'Anna // Split out a line from the buffer, if there is a full one to get. 293b3faa01fSLawrence D'Anna static Optional<std::string> SplitLine(std::string &line_buffer) { 294b3faa01fSLawrence D'Anna size_t pos = line_buffer.find('\n'); 295b3faa01fSLawrence D'Anna if (pos == std::string::npos) 296b3faa01fSLawrence D'Anna return None; 297adcd0268SBenjamin Kramer std::string line = 298adcd0268SBenjamin Kramer std::string(StringRef(line_buffer.c_str(), pos).rtrim("\n\r")); 299b3faa01fSLawrence D'Anna line_buffer = line_buffer.substr(pos + 1); 300b3faa01fSLawrence D'Anna return line; 301b3faa01fSLawrence D'Anna } 302b3faa01fSLawrence D'Anna 303b3faa01fSLawrence D'Anna // If the final line of the file ends without a end-of-line, return 304b3faa01fSLawrence D'Anna // it as a line anyway. 305b3faa01fSLawrence D'Anna static Optional<std::string> SplitLineEOF(std::string &line_buffer) { 306b3faa01fSLawrence D'Anna if (llvm::all_of(line_buffer, isspace)) 307b3faa01fSLawrence D'Anna return None; 308b3faa01fSLawrence D'Anna std::string line = std::move(line_buffer); 309b3faa01fSLawrence D'Anna line_buffer.clear(); 310b3faa01fSLawrence D'Anna return line; 311b3faa01fSLawrence D'Anna } 312b3faa01fSLawrence D'Anna 313b9c1b51eSKate Stone bool IOHandlerEditline::GetLine(std::string &line, bool &interrupted) { 31462456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 315d5b44036SJonas Devlieghere if (m_editline_up) { 316d77c2e09SJonas Devlieghere bool b = m_editline_up->GetLine(line, interrupted); 317b3faa01fSLawrence D'Anna if (b && m_data_recorder) 318d77c2e09SJonas Devlieghere m_data_recorder->Record(line, true); 319d77c2e09SJonas Devlieghere return b; 320b3faa01fSLawrence D'Anna } 321cacde7dfSTodd Fiala #endif 322b3faa01fSLawrence D'Anna 32344d93782SGreg Clayton line.clear(); 32444d93782SGreg Clayton 325b9c1b51eSKate Stone if (GetIsInteractive()) { 326c5dac77aSEugene Zelenko const char *prompt = nullptr; 327e30f11d9SKate Stone 328e30f11d9SKate Stone if (m_multi_line && m_curr_line_idx > 0) 329e30f11d9SKate Stone prompt = GetContinuationPrompt(); 330e30f11d9SKate Stone 331c5dac77aSEugene Zelenko if (prompt == nullptr) 332e30f11d9SKate Stone prompt = GetPrompt(); 333e30f11d9SKate Stone 334b9c1b51eSKate Stone if (prompt && prompt[0]) { 3355da2bc22SLawrence D'Anna if (m_output_sp) { 3365da2bc22SLawrence D'Anna m_output_sp->Printf("%s", prompt); 3375da2bc22SLawrence D'Anna m_output_sp->Flush(); 33844d93782SGreg Clayton } 33944d93782SGreg Clayton } 34044d93782SGreg Clayton } 341b3faa01fSLawrence D'Anna 342b3faa01fSLawrence D'Anna Optional<std::string> got_line = SplitLine(m_line_buffer); 343b3faa01fSLawrence D'Anna 344b3faa01fSLawrence D'Anna if (!got_line && !m_input_sp) { 345b3faa01fSLawrence D'Anna // No more input file, we are done... 346b3faa01fSLawrence D'Anna SetIsDone(true); 347b3faa01fSLawrence D'Anna return false; 348b3faa01fSLawrence D'Anna } 349b3faa01fSLawrence D'Anna 350b3faa01fSLawrence D'Anna FILE *in = GetInputFILE(); 35144d93782SGreg Clayton char buffer[256]; 352b3faa01fSLawrence D'Anna 353b3faa01fSLawrence D'Anna if (!got_line && !in && m_input_sp) { 354b3faa01fSLawrence D'Anna // there is no FILE*, fall back on just reading bytes from the stream. 355b3faa01fSLawrence D'Anna while (!got_line) { 356b3faa01fSLawrence D'Anna size_t bytes_read = sizeof(buffer); 357b3faa01fSLawrence D'Anna Status error = m_input_sp->Read((void *)buffer, bytes_read); 358b3faa01fSLawrence D'Anna if (error.Success() && !bytes_read) { 359b3faa01fSLawrence D'Anna got_line = SplitLineEOF(m_line_buffer); 360b3faa01fSLawrence D'Anna break; 361b3faa01fSLawrence D'Anna } 362b3faa01fSLawrence D'Anna if (error.Fail()) 363b3faa01fSLawrence D'Anna break; 364b3faa01fSLawrence D'Anna m_line_buffer += StringRef(buffer, bytes_read); 365b3faa01fSLawrence D'Anna got_line = SplitLine(m_line_buffer); 366b3faa01fSLawrence D'Anna } 367b3faa01fSLawrence D'Anna } 368b3faa01fSLawrence D'Anna 369b3faa01fSLawrence D'Anna if (!got_line && in) { 370e034a04eSGreg Clayton m_editing = true; 371b3faa01fSLawrence D'Anna while (!got_line) { 372b3faa01fSLawrence D'Anna char *r = fgets(buffer, sizeof(buffer), in); 373e7167908SNathan Lanza #ifdef _WIN32 374e7167908SNathan Lanza // ReadFile on Windows is supposed to set ERROR_OPERATION_ABORTED 375e7167908SNathan Lanza // according to the docs on MSDN. However, this has evidently been a 376e7167908SNathan Lanza // known bug since Windows 8. Therefore, we can't detect if a signal 377e7167908SNathan Lanza // interrupted in the fgets. So pressing ctrl-c causes the repl to end 378e7167908SNathan Lanza // and the process to exit. A temporary workaround is just to attempt to 379e7167908SNathan Lanza // fgets twice until this bug is fixed. 380b3faa01fSLawrence D'Anna if (r == nullptr) 381b3faa01fSLawrence D'Anna r = fgets(buffer, sizeof(buffer), in); 382cb305205SNathan Lanza // this is the equivalent of EINTR for Windows 383b3faa01fSLawrence D'Anna if (r == nullptr && GetLastError() == ERROR_OPERATION_ABORTED) 384cb305205SNathan Lanza continue; 385e7167908SNathan Lanza #endif 386b3faa01fSLawrence D'Anna if (r == nullptr) { 387b3faa01fSLawrence D'Anna if (ferror(in) && errno == EINTR) 388b3faa01fSLawrence D'Anna continue; 389c9cf5798SGreg Clayton if (feof(in)) 390b3faa01fSLawrence D'Anna got_line = SplitLineEOF(m_line_buffer); 39144d93782SGreg Clayton break; 39244d93782SGreg Clayton } 393b3faa01fSLawrence D'Anna m_line_buffer += buffer; 394b3faa01fSLawrence D'Anna got_line = SplitLine(m_line_buffer); 39544d93782SGreg Clayton } 396e034a04eSGreg Clayton m_editing = false; 397b3faa01fSLawrence D'Anna } 398b3faa01fSLawrence D'Anna 399b3faa01fSLawrence D'Anna if (got_line) { 400b3faa01fSLawrence D'Anna line = got_line.getValue(); 401b3faa01fSLawrence D'Anna if (m_data_recorder) 402d77c2e09SJonas Devlieghere m_data_recorder->Record(line, true); 40344d93782SGreg Clayton } 404b3faa01fSLawrence D'Anna 405b3faa01fSLawrence D'Anna return (bool)got_line; 40644d93782SGreg Clayton } 40744d93782SGreg Clayton 40862456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 409b9c1b51eSKate Stone bool IOHandlerEditline::IsInputCompleteCallback(Editline *editline, 41044d93782SGreg Clayton StringList &lines, 411b9c1b51eSKate Stone void *baton) { 41244d93782SGreg Clayton IOHandlerEditline *editline_reader = (IOHandlerEditline *)baton; 413b9c1b51eSKate Stone return editline_reader->m_delegate.IOHandlerIsInputComplete(*editline_reader, 414b9c1b51eSKate Stone lines); 415e30f11d9SKate Stone } 416e30f11d9SKate Stone 417b9c1b51eSKate Stone int IOHandlerEditline::FixIndentationCallback(Editline *editline, 418e30f11d9SKate Stone const StringList &lines, 419e30f11d9SKate Stone int cursor_position, 420b9c1b51eSKate Stone void *baton) { 421e30f11d9SKate Stone IOHandlerEditline *editline_reader = (IOHandlerEditline *)baton; 422b9c1b51eSKate Stone return editline_reader->m_delegate.IOHandlerFixIndentation( 423b9c1b51eSKate Stone *editline_reader, lines, cursor_position); 42444d93782SGreg Clayton } 42544d93782SGreg Clayton 426ae34ed2cSRaphael Isemann void IOHandlerEditline::AutoCompleteCallback(CompletionRequest &request, 4272fc20f65SRaphael Isemann void *baton) { 42844d93782SGreg Clayton IOHandlerEditline *editline_reader = (IOHandlerEditline *)baton; 42944d93782SGreg Clayton if (editline_reader) 430ae34ed2cSRaphael Isemann editline_reader->m_delegate.IOHandlerComplete(*editline_reader, request); 43144d93782SGreg Clayton } 432cacde7dfSTodd Fiala #endif 43344d93782SGreg Clayton 434b9c1b51eSKate Stone const char *IOHandlerEditline::GetPrompt() { 43562456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 436d5b44036SJonas Devlieghere if (m_editline_up) { 437d5b44036SJonas Devlieghere return m_editline_up->GetPrompt(); 438b9c1b51eSKate Stone } else { 439cacde7dfSTodd Fiala #endif 440cacde7dfSTodd Fiala if (m_prompt.empty()) 441c5dac77aSEugene Zelenko return nullptr; 44262456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 443cacde7dfSTodd Fiala } 444cacde7dfSTodd Fiala #endif 44544d93782SGreg Clayton return m_prompt.c_str(); 44644d93782SGreg Clayton } 44744d93782SGreg Clayton 448514d8cd8SZachary Turner bool IOHandlerEditline::SetPrompt(llvm::StringRef prompt) { 449adcd0268SBenjamin Kramer m_prompt = std::string(prompt); 450514d8cd8SZachary Turner 45162456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 452d5b44036SJonas Devlieghere if (m_editline_up) 453d5b44036SJonas Devlieghere m_editline_up->SetPrompt(m_prompt.empty() ? nullptr : m_prompt.c_str()); 454cacde7dfSTodd Fiala #endif 45544d93782SGreg Clayton return true; 45644d93782SGreg Clayton } 45744d93782SGreg Clayton 458b9c1b51eSKate Stone const char *IOHandlerEditline::GetContinuationPrompt() { 459b9c1b51eSKate Stone return (m_continuation_prompt.empty() ? nullptr 460b9c1b51eSKate Stone : m_continuation_prompt.c_str()); 461e30f11d9SKate Stone } 462e30f11d9SKate Stone 463514d8cd8SZachary Turner void IOHandlerEditline::SetContinuationPrompt(llvm::StringRef prompt) { 464adcd0268SBenjamin Kramer m_continuation_prompt = std::string(prompt); 465e30f11d9SKate Stone 46662456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 467d5b44036SJonas Devlieghere if (m_editline_up) 468d5b44036SJonas Devlieghere m_editline_up->SetContinuationPrompt(m_continuation_prompt.empty() 469b9c1b51eSKate Stone ? nullptr 470b9c1b51eSKate Stone : m_continuation_prompt.c_str()); 471d553d00cSZachary Turner #endif 472e30f11d9SKate Stone } 473e30f11d9SKate Stone 474b9c1b51eSKate Stone void IOHandlerEditline::SetBaseLineNumber(uint32_t line) { 475f6913cd7SGreg Clayton m_base_line_number = line; 476f6913cd7SGreg Clayton } 477e30f11d9SKate Stone 478b9c1b51eSKate Stone uint32_t IOHandlerEditline::GetCurrentLineIndex() const { 47962456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 480d5b44036SJonas Devlieghere if (m_editline_up) 481d5b44036SJonas Devlieghere return m_editline_up->GetCurrentLine(); 482e30f11d9SKate Stone #endif 483e30f11d9SKate Stone return m_curr_line_idx; 484e30f11d9SKate Stone } 485e30f11d9SKate Stone 486b9c1b51eSKate Stone bool IOHandlerEditline::GetLines(StringList &lines, bool &interrupted) { 487e30f11d9SKate Stone m_current_lines_ptr = &lines; 488e30f11d9SKate Stone 48944d93782SGreg Clayton bool success = false; 49062456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 491d5b44036SJonas Devlieghere if (m_editline_up) { 492d5b44036SJonas Devlieghere return m_editline_up->GetLines(m_base_line_number, lines, interrupted); 493b9c1b51eSKate Stone } else { 494cacde7dfSTodd Fiala #endif 495e30f11d9SKate Stone bool done = false; 49697206d57SZachary Turner Status error; 49744d93782SGreg Clayton 498b9c1b51eSKate Stone while (!done) { 499f6913cd7SGreg Clayton // Show line numbers if we are asked to 50044d93782SGreg Clayton std::string line; 501b9c1b51eSKate Stone if (m_base_line_number > 0 && GetIsInteractive()) { 5025da2bc22SLawrence D'Anna if (m_output_sp) { 5035da2bc22SLawrence D'Anna m_output_sp->Printf("%u%s", 5045da2bc22SLawrence D'Anna m_base_line_number + (uint32_t)lines.GetSize(), 505b9c1b51eSKate Stone GetPrompt() == nullptr ? " " : ""); 506f6913cd7SGreg Clayton } 5075da2bc22SLawrence D'Anna } 508f6913cd7SGreg Clayton 509e30f11d9SKate Stone m_curr_line_idx = lines.GetSize(); 510e30f11d9SKate Stone 511f0066ad0SGreg Clayton bool interrupted = false; 512b9c1b51eSKate Stone if (GetLine(line, interrupted) && !interrupted) { 51344d93782SGreg Clayton lines.AppendString(line); 514e30f11d9SKate Stone done = m_delegate.IOHandlerIsInputComplete(*this, lines); 515b9c1b51eSKate Stone } else { 516e30f11d9SKate Stone done = true; 51744d93782SGreg Clayton } 51844d93782SGreg Clayton } 51944d93782SGreg Clayton success = lines.GetSize() > 0; 52062456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 52144d93782SGreg Clayton } 522cacde7dfSTodd Fiala #endif 52344d93782SGreg Clayton return success; 52444d93782SGreg Clayton } 52544d93782SGreg Clayton 52605097246SAdrian Prantl // Each IOHandler gets to run until it is done. It should read data from the 52705097246SAdrian Prantl // "in" and place output into "out" and "err and return when done. 528b9c1b51eSKate Stone void IOHandlerEditline::Run() { 52944d93782SGreg Clayton std::string line; 530b9c1b51eSKate Stone while (IsActive()) { 531f0066ad0SGreg Clayton bool interrupted = false; 532b9c1b51eSKate Stone if (m_multi_line) { 53344d93782SGreg Clayton StringList lines; 534b9c1b51eSKate Stone if (GetLines(lines, interrupted)) { 535b9c1b51eSKate Stone if (interrupted) { 536e30f11d9SKate Stone m_done = m_interrupt_exits; 537e30f11d9SKate Stone m_delegate.IOHandlerInputInterrupted(*this, line); 538e30f11d9SKate Stone 539b9c1b51eSKate Stone } else { 54044d93782SGreg Clayton line = lines.CopyList(); 54144d93782SGreg Clayton m_delegate.IOHandlerInputComplete(*this, line); 54244d93782SGreg Clayton } 543b9c1b51eSKate Stone } else { 54444d93782SGreg Clayton m_done = true; 54544d93782SGreg Clayton } 546b9c1b51eSKate Stone } else { 547b9c1b51eSKate Stone if (GetLine(line, interrupted)) { 548e30f11d9SKate Stone if (interrupted) 549e30f11d9SKate Stone m_delegate.IOHandlerInputInterrupted(*this, line); 550e30f11d9SKate Stone else 55144d93782SGreg Clayton m_delegate.IOHandlerInputComplete(*this, line); 552b9c1b51eSKate Stone } else { 55344d93782SGreg Clayton m_done = true; 55444d93782SGreg Clayton } 55544d93782SGreg Clayton } 55644d93782SGreg Clayton } 55744d93782SGreg Clayton } 55844d93782SGreg Clayton 559b9c1b51eSKate Stone void IOHandlerEditline::Cancel() { 56062456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 561d5b44036SJonas Devlieghere if (m_editline_up) 562d5b44036SJonas Devlieghere m_editline_up->Cancel(); 563cacde7dfSTodd Fiala #endif 564e68f5d6bSGreg Clayton } 565e68f5d6bSGreg Clayton 566b9c1b51eSKate Stone bool IOHandlerEditline::Interrupt() { 567f0066ad0SGreg Clayton // Let the delgate handle it first 568f0066ad0SGreg Clayton if (m_delegate.IOHandlerInterrupt(*this)) 569f0066ad0SGreg Clayton return true; 570f0066ad0SGreg Clayton 57162456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 572d5b44036SJonas Devlieghere if (m_editline_up) 573d5b44036SJonas Devlieghere return m_editline_up->Interrupt(); 574cacde7dfSTodd Fiala #endif 575f0066ad0SGreg Clayton return false; 57644d93782SGreg Clayton } 57744d93782SGreg Clayton 578b9c1b51eSKate Stone void IOHandlerEditline::GotEOF() { 57962456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 580d5b44036SJonas Devlieghere if (m_editline_up) 581d5b44036SJonas Devlieghere m_editline_up->Interrupt(); 582cacde7dfSTodd Fiala #endif 58344d93782SGreg Clayton } 58444d93782SGreg Clayton 585b9c1b51eSKate Stone void IOHandlerEditline::PrintAsync(Stream *stream, const char *s, size_t len) { 58662456e57SJonas Devlieghere #if LLDB_ENABLE_LIBEDIT 587d5b44036SJonas Devlieghere if (m_editline_up) 588d5b44036SJonas Devlieghere m_editline_up->PrintAsync(stream, s, len); 5894446487dSPavel Labath else 5904446487dSPavel Labath #endif 591fab31220STed Woodward { 5928b98f12aSMartin Storsjo #ifdef _WIN32 593341e4789SDawn Perchik const char *prompt = GetPrompt(); 594b9c1b51eSKate Stone if (prompt) { 595fab31220STed Woodward // Back up over previous prompt using Windows API 596fab31220STed Woodward CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; 597fab31220STed Woodward HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE); 598fab31220STed Woodward GetConsoleScreenBufferInfo(console_handle, &screen_buffer_info); 599fab31220STed Woodward COORD coord = screen_buffer_info.dwCursorPosition; 600fab31220STed Woodward coord.X -= strlen(prompt); 601fab31220STed Woodward if (coord.X < 0) 602fab31220STed Woodward coord.X = 0; 603fab31220STed Woodward SetConsoleCursorPosition(console_handle, coord); 604fab31220STed Woodward } 605fab31220STed Woodward #endif 6064446487dSPavel Labath IOHandler::PrintAsync(stream, s, len); 6078b98f12aSMartin Storsjo #ifdef _WIN32 608fab31220STed Woodward if (prompt) 6097ca15ba7SLawrence D'Anna IOHandler::PrintAsync(GetOutputStreamFileSP().get(), prompt, 610b9c1b51eSKate Stone strlen(prompt)); 611341e4789SDawn Perchik #endif 612fab31220STed Woodward } 6134446487dSPavel Labath } 614