Coverage Report

Created: 2023-09-12 09:32

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Core/IOHandler.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- IOHandler.cpp -----------------------------------------------------===//
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/Core/IOHandler.h"
10
11
#if defined(__APPLE__)
12
#include <deque>
13
#endif
14
#include <string>
15
16
#include "lldb/Core/Debugger.h"
17
#include "lldb/Host/Config.h"
18
#include "lldb/Host/File.h"
19
#include "lldb/Host/StreamFile.h"
20
#include "lldb/Utility/AnsiTerminal.h"
21
#include "lldb/Utility/Predicate.h"
22
#include "lldb/Utility/Status.h"
23
#include "lldb/Utility/StreamString.h"
24
#include "lldb/Utility/StringList.h"
25
#include "lldb/lldb-forward.h"
26
27
#if LLDB_ENABLE_LIBEDIT
28
#include "lldb/Host/Editline.h"
29
#endif
30
#include "lldb/Interpreter/CommandCompletions.h"
31
#include "lldb/Interpreter/CommandInterpreter.h"
32
#include "llvm/ADT/StringRef.h"
33
34
#ifdef _WIN32
35
#include "lldb/Host/windows/windows.h"
36
#endif
37
38
#include <memory>
39
#include <mutex>
40
#include <optional>
41
42
#include <cassert>
43
#include <cctype>
44
#include <cerrno>
45
#include <clocale>
46
#include <cstdint>
47
#include <cstdio>
48
#include <cstring>
49
#include <type_traits>
50
51
using namespace lldb;
52
using namespace lldb_private;
53
using llvm::StringRef;
54
55
IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type)
56
    : IOHandler(debugger, type,
57
                FileSP(),       // Adopt STDIN from top input reader
58
                StreamFileSP(), // Adopt STDOUT from top input reader
59
                StreamFileSP(), // Adopt STDERR from top input reader
60
                0               // Flags
61
62
2.09k
      ) {}
63
64
IOHandler::IOHandler(Debugger &debugger, IOHandler::Type type,
65
                     const lldb::FileSP &input_sp,
66
                     const lldb::StreamFileSP &output_sp,
67
                     const lldb::StreamFileSP &error_sp, uint32_t flags)
68
    : m_debugger(debugger), m_input_sp(input_sp), m_output_sp(output_sp),
69
      m_error_sp(error_sp), m_popped(false), m_flags(flags), m_type(type),
70
3.54k
      m_user_data(nullptr), m_done(false), m_active(false) {
71
  // If any files are not specified, then adopt them from the top input reader.
72
3.54k
  if (!m_input_sp || 
!m_output_sp1.42k
||
!m_error_sp531
)
73
3.01k
    debugger.AdoptTopIOHandlerFilesIfInvalid(m_input_sp, m_output_sp,
74
3.01k
                                             m_error_sp);
75
3.54k
}
76
77
3.54k
IOHandler::~IOHandler() = default;
78
79
2.09k
int IOHandler::GetInputFD() {
80
2.09k
  return (m_input_sp ? m_input_sp->GetDescriptor() : 
-10
);
81
2.09k
}
82
83
0
int IOHandler::GetOutputFD() {
84
0
  return (m_output_sp ? m_output_sp->GetFile().GetDescriptor() : -1);
85
0
}
86
87
0
int IOHandler::GetErrorFD() {
88
0
  return (m_error_sp ? m_error_sp->GetFile().GetDescriptor() : -1);
89
0
}
90
91
10.2k
FILE *IOHandler::GetInputFILE() {
92
10.2k
  return (m_input_sp ? m_input_sp->GetStream() : 
nullptr0
);
93
10.2k
}
94
95
1.45k
FILE *IOHandler::GetOutputFILE() {
96
1.45k
  return (m_output_sp ? m_output_sp->GetFile().GetStream() : 
nullptr0
);
97
1.45k
}
98
99
1.45k
FILE *IOHandler::GetErrorFILE() {
100
1.45k
  return (m_error_sp ? m_error_sp->GetFile().GetStream() : 
nullptr0
);
101
1.45k
}
102
103
38.3k
FileSP IOHandler::GetInputFileSP() { return m_input_sp; }
104
105
8.21k
StreamFileSP IOHandler::GetOutputStreamFileSP() { return m_output_sp; }
106
107
5.84k
StreamFileSP IOHandler::GetErrorStreamFileSP() { return m_error_sp; }
108
109
18.7k
bool IOHandler::GetIsInteractive() {
110
18.7k
  return GetInputFileSP() ? GetInputFileSP()->GetIsInteractive() : 
false0
;
111
18.7k
}
112
113
0
bool IOHandler::GetIsRealTerminal() {
114
0
  return GetInputFileSP() ? GetInputFileSP()->GetIsRealTerminal() : false;
115
0
}
116
117
16.2k
void IOHandler::SetPopped(bool b) { m_popped.SetValue(b, eBroadcastOnChange); }
118
119
0
void IOHandler::WaitForPop() { m_popped.WaitForValueEqualTo(true); }
120
121
1.95k
void IOHandler::PrintAsync(const char *s, size_t len, bool is_stdout) {
122
1.95k
  std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
123
1.95k
  lldb::StreamFileSP stream = is_stdout ? 
m_output_sp1.93k
:
m_error_sp24
;
124
1.95k
  stream->Write(s, len);
125
1.95k
  stream->Flush();
126
1.95k
}
127
128
2.47k
bool IOHandlerStack::PrintAsync(const char *s, size_t len, bool is_stdout) {
129
2.47k
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
130
2.47k
  if (!m_top)
131
184
    return false;
132
2.29k
  m_top->PrintAsync(s, len, is_stdout);
133
2.29k
  return true;
134
2.47k
}
135
136
IOHandlerConfirm::IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt,
137
                                   bool default_response)
138
    : IOHandlerEditline(
139
          debugger, IOHandler::Type::Confirm,
140
          nullptr, // nullptr editline_name means no history loaded/saved
141
          llvm::StringRef(), // No prompt
142
          llvm::StringRef(), // No continuation prompt
143
          false,             // Multi-line
144
          false, // Don't colorize the prompt (i.e. the confirm message.)
145
          0, *this),
146
14
      m_default_response(default_response), m_user_response(default_response) {
147
14
  StreamString prompt_stream;
148
14
  prompt_stream.PutCString(prompt);
149
14
  if (m_default_response)
150
14
    prompt_stream.Printf(": [Y/n] ");
151
0
  else
152
0
    prompt_stream.Printf(": [y/N] ");
153
154
14
  SetPrompt(prompt_stream.GetString());
155
14
}
156
157
14
IOHandlerConfirm::~IOHandlerConfirm() = default;
158
159
void IOHandlerConfirm::IOHandlerComplete(IOHandler &io_handler,
160
0
                                         CompletionRequest &request) {
161
0
  if (request.GetRawCursorPos() != 0)
162
0
    return;
163
0
  request.AddCompletion(m_default_response ? "y" : "n");
164
0
}
165
166
void IOHandlerConfirm::IOHandlerInputComplete(IOHandler &io_handler,
167
1
                                              std::string &line) {
168
1
  if (line.empty()) {
169
    // User just hit enter, set the response to the default
170
1
    m_user_response = m_default_response;
171
1
    io_handler.SetIsDone(true);
172
1
    return;
173
1
  }
174
175
0
  if (line.size() == 1) {
176
0
    switch (line[0]) {
177
0
    case 'y':
178
0
    case 'Y':
179
0
      m_user_response = true;
180
0
      io_handler.SetIsDone(true);
181
0
      return;
182
0
    case 'n':
183
0
    case 'N':
184
0
      m_user_response = false;
185
0
      io_handler.SetIsDone(true);
186
0
      return;
187
0
    default:
188
0
      break;
189
0
    }
190
0
  }
191
192
0
  if (line == "yes" || line == "YES" || line == "Yes") {
193
0
    m_user_response = true;
194
0
    io_handler.SetIsDone(true);
195
0
  } else if (line == "no" || line == "NO" || line == "No") {
196
0
    m_user_response = false;
197
0
    io_handler.SetIsDone(true);
198
0
  }
199
0
}
200
201
std::optional<std::string>
202
IOHandlerDelegate::IOHandlerSuggestion(IOHandler &io_handler,
203
0
                                       llvm::StringRef line) {
204
0
  return io_handler.GetDebugger()
205
0
      .GetCommandInterpreter()
206
0
      .GetAutoSuggestionForCommand(line);
207
0
}
208
209
void IOHandlerDelegate::IOHandlerComplete(IOHandler &io_handler,
210
0
                                          CompletionRequest &request) {
211
0
  switch (m_completion) {
212
0
  case Completion::None:
213
0
    break;
214
0
  case Completion::LLDBCommand:
215
0
    io_handler.GetDebugger().GetCommandInterpreter().HandleCompletion(request);
216
0
    break;
217
0
  case Completion::Expression:
218
0
    lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
219
0
        io_handler.GetDebugger().GetCommandInterpreter(),
220
0
        lldb::eVariablePathCompletion, request, nullptr);
221
0
    break;
222
0
  }
223
0
}
224
225
IOHandlerEditline::IOHandlerEditline(
226
    Debugger &debugger, IOHandler::Type type,
227
    const char *editline_name, // Used for saving history files
228
    llvm::StringRef prompt, llvm::StringRef continuation_prompt,
229
    bool multi_line, bool color_prompts, uint32_t line_number_start,
230
    IOHandlerDelegate &delegate)
231
    : IOHandlerEditline(debugger, type,
232
                        FileSP(),       // Inherit input from top input reader
233
                        StreamFileSP(), // Inherit output from top input reader
234
                        StreamFileSP(), // Inherit error from top input reader
235
                        0,              // Flags
236
                        editline_name,  // Used for saving history files
237
                        prompt, continuation_prompt, multi_line, color_prompts,
238
21
                        line_number_start, delegate) {}
lldb_private::IOHandlerEditline::IOHandlerEditline(lldb_private::Debugger&, lldb_private::IOHandler::Type, char const*, llvm::StringRef, llvm::StringRef, bool, bool, unsigned int, lldb_private::IOHandlerDelegate&)
Line
Count
Source
238
14
                        line_number_start, delegate) {}
lldb_private::IOHandlerEditline::IOHandlerEditline(lldb_private::Debugger&, lldb_private::IOHandler::Type, char const*, llvm::StringRef, llvm::StringRef, bool, bool, unsigned int, lldb_private::IOHandlerDelegate&)
Line
Count
Source
238
7
                        line_number_start, delegate) {}
239
240
IOHandlerEditline::IOHandlerEditline(
241
    Debugger &debugger, IOHandler::Type type, const lldb::FileSP &input_sp,
242
    const lldb::StreamFileSP &output_sp, const lldb::StreamFileSP &error_sp,
243
    uint32_t flags,
244
    const char *editline_name, // Used for saving history files
245
    llvm::StringRef prompt, llvm::StringRef continuation_prompt,
246
    bool multi_line, bool color_prompts, uint32_t line_number_start,
247
    IOHandlerDelegate &delegate)
248
    : IOHandler(debugger, type, input_sp, output_sp, error_sp, flags),
249
#if LLDB_ENABLE_LIBEDIT
250
      m_editline_up(),
251
#endif
252
      m_delegate(delegate), m_prompt(), m_continuation_prompt(),
253
      m_current_lines_ptr(nullptr), m_base_line_number(line_number_start),
254
      m_curr_line_idx(UINT32_MAX), m_multi_line(multi_line),
255
1.45k
      m_color_prompts(color_prompts), m_interrupt_exits(true) {
256
1.45k
  SetPrompt(prompt);
257
258
1.45k
#if LLDB_ENABLE_LIBEDIT
259
1.45k
  bool use_editline = false;
260
261
1.45k
  use_editline = GetInputFILE() && 
GetOutputFILE()1.44k
&&
GetErrorFILE()1.44k
&&
262
1.45k
                 
m_input_sp1.44k
&&
m_input_sp->GetIsRealTerminal()1.44k
;
263
264
1.45k
  if (use_editline) {
265
9
    m_editline_up = std::make_unique<Editline>(
266
9
        editline_name, GetInputFILE(), GetOutputFILE(), GetErrorFILE(),
267
9
        GetOutputMutex(), m_color_prompts);
268
9
    m_editline_up->SetIsInputCompleteCallback(
269
9
        [this](Editline *editline, StringList &lines) {
270
1
          return this->IsInputCompleteCallback(editline, lines);
271
1
        });
272
273
9
    m_editline_up->SetAutoCompleteCallback([this](CompletionRequest &request) {
274
0
      this->AutoCompleteCallback(request);
275
0
    });
276
277
9
    if (debugger.GetUseAutosuggestion()) {
278
0
      m_editline_up->SetSuggestionCallback([this](llvm::StringRef line) {
279
0
        return this->SuggestionCallback(line);
280
0
      });
281
0
      m_editline_up->SetSuggestionAnsiPrefix(ansi::FormatAnsiTerminalCodes(
282
0
          debugger.GetAutosuggestionAnsiPrefix()));
283
0
      m_editline_up->SetSuggestionAnsiSuffix(ansi::FormatAnsiTerminalCodes(
284
0
          debugger.GetAutosuggestionAnsiSuffix()));
285
0
    }
286
    // See if the delegate supports fixing indentation
287
9
    const char *indent_chars = delegate.IOHandlerGetFixIndentationCharacters();
288
9
    if (indent_chars) {
289
      // The delegate does support indentation, hook it up so when any
290
      // indentation character is typed, the delegate gets a chance to fix it
291
0
      FixIndentationCallbackType f = [this](Editline *editline,
292
0
                                            const StringList &lines,
293
0
                                            int cursor_position) {
294
0
        return this->FixIndentationCallback(editline, lines, cursor_position);
295
0
      };
296
0
      m_editline_up->SetFixIndentationCallback(std::move(f), indent_chars);
297
0
    }
298
9
  }
299
1.45k
#endif
300
1.45k
  SetBaseLineNumber(m_base_line_number);
301
1.45k
  SetPrompt(prompt);
302
1.45k
  SetContinuationPrompt(continuation_prompt);
303
1.45k
}
304
305
1.45k
IOHandlerEditline::~IOHandlerEditline() {
306
1.45k
#if LLDB_ENABLE_LIBEDIT
307
1.45k
  m_editline_up.reset();
308
1.45k
#endif
309
1.45k
}
310
311
2.48k
void IOHandlerEditline::Activate() {
312
2.48k
  IOHandler::Activate();
313
2.48k
  m_delegate.IOHandlerActivated(*this, GetIsInteractive());
314
2.48k
}
315
316
2.48k
void IOHandlerEditline::Deactivate() {
317
2.48k
  IOHandler::Deactivate();
318
2.48k
  m_delegate.IOHandlerDeactivated(*this);
319
2.48k
}
320
321
0
void IOHandlerEditline::TerminalSizeChanged() {
322
0
#if LLDB_ENABLE_LIBEDIT
323
0
  if (m_editline_up)
324
0
    m_editline_up->TerminalSizeChanged();
325
0
#endif
326
0
}
327
328
// Split out a line from the buffer, if there is a full one to get.
329
16.2k
static std::optional<std::string> SplitLine(std::string &line_buffer) {
330
16.2k
  size_t pos = line_buffer.find('\n');
331
16.2k
  if (pos == std::string::npos)
332
8.79k
    return std::nullopt;
333
7.48k
  std::string line =
334
7.48k
      std::string(StringRef(line_buffer.c_str(), pos).rtrim("\n\r"));
335
7.48k
  line_buffer = line_buffer.substr(pos + 1);
336
7.48k
  return line;
337
16.2k
}
338
339
// If the final line of the file ends without a end-of-line, return
340
// it as a line anyway.
341
1.28k
static std::optional<std::string> SplitLineEOF(std::string &line_buffer) {
342
1.28k
  if (llvm::all_of(line_buffer, llvm::isSpace))
343
1.28k
    return std::nullopt;
344
3
  std::string line = std::move(line_buffer);
345
3
  line_buffer.clear();
346
3
  return line;
347
1.28k
}
348
349
8.82k
bool IOHandlerEditline::GetLine(std::string &line, bool &interrupted) {
350
8.82k
#if LLDB_ENABLE_LIBEDIT
351
8.82k
  if (m_editline_up) {
352
44
    return m_editline_up->GetLine(line, interrupted);
353
44
  }
354
8.77k
#endif
355
356
8.77k
  line.clear();
357
358
8.77k
  if (GetIsInteractive()) {
359
0
    const char *prompt = nullptr;
360
361
0
    if (m_multi_line && m_curr_line_idx > 0)
362
0
      prompt = GetContinuationPrompt();
363
364
0
    if (prompt == nullptr)
365
0
      prompt = GetPrompt();
366
367
0
    if (prompt && prompt[0]) {
368
0
      if (m_output_sp) {
369
0
        m_output_sp->Printf("%s", prompt);
370
0
        m_output_sp->Flush();
371
0
      }
372
0
    }
373
0
  }
374
375
8.77k
  std::optional<std::string> got_line = SplitLine(m_line_buffer);
376
377
8.77k
  if (!got_line && 
!m_input_sp8.77k
) {
378
    // No more input file, we are done...
379
0
    SetIsDone(true);
380
0
    return false;
381
0
  }
382
383
8.77k
  FILE *in = GetInputFILE();
384
8.77k
  char buffer[256];
385
386
8.77k
  if (!got_line && 
!in8.77k
&&
m_input_sp5
) {
387
    // there is no FILE*, fall back on just reading bytes from the stream.
388
7
    while (!got_line) {
389
5
      size_t bytes_read = sizeof(buffer);
390
5
      Status error = m_input_sp->Read((void *)buffer, bytes_read);
391
5
      if (error.Success() && 
!bytes_read4
) {
392
2
        got_line = SplitLineEOF(m_line_buffer);
393
2
        break;
394
2
      }
395
3
      if (error.Fail())
396
1
        break;
397
2
      m_line_buffer += StringRef(buffer, bytes_read);
398
2
      got_line = SplitLine(m_line_buffer);
399
2
    }
400
5
  }
401
402
8.77k
  if (!got_line && 
in8.77k
) {
403
16.2k
    while (!got_line) {
404
8.79k
      char *r = fgets(buffer, sizeof(buffer), in);
405
#ifdef _WIN32
406
      // ReadFile on Windows is supposed to set ERROR_OPERATION_ABORTED
407
      // according to the docs on MSDN. However, this has evidently been a
408
      // known bug since Windows 8. Therefore, we can't detect if a signal
409
      // interrupted in the fgets. So pressing ctrl-c causes the repl to end
410
      // and the process to exit. A temporary workaround is just to attempt to
411
      // fgets twice until this bug is fixed.
412
      if (r == nullptr)
413
        r = fgets(buffer, sizeof(buffer), in);
414
      // this is the equivalent of EINTR for Windows
415
      if (r == nullptr && GetLastError() == ERROR_OPERATION_ABORTED)
416
        continue;
417
#endif
418
8.79k
      if (r == nullptr) {
419
1.28k
        if (ferror(in) && errno
== EINTR0
)
420
0
          continue;
421
1.28k
        if (feof(in))
422
1.28k
          got_line = SplitLineEOF(m_line_buffer);
423
1.28k
        break;
424
1.28k
      }
425
7.50k
      m_line_buffer += buffer;
426
7.50k
      got_line = SplitLine(m_line_buffer);
427
7.50k
    }
428
8.76k
  }
429
430
8.77k
  if (got_line) {
431
7.49k
    line = *got_line;
432
7.49k
  }
433
434
8.77k
  return (bool)got_line;
435
8.77k
}
436
437
#if LLDB_ENABLE_LIBEDIT
438
bool IOHandlerEditline::IsInputCompleteCallback(Editline *editline,
439
1
                                                StringList &lines) {
440
1
  return m_delegate.IOHandlerIsInputComplete(*this, lines);
441
1
}
442
443
int IOHandlerEditline::FixIndentationCallback(Editline *editline,
444
                                              const StringList &lines,
445
0
                                              int cursor_position) {
446
0
  return m_delegate.IOHandlerFixIndentation(*this, lines, cursor_position);
447
0
}
448
449
std::optional<std::string>
450
0
IOHandlerEditline::SuggestionCallback(llvm::StringRef line) {
451
0
  return m_delegate.IOHandlerSuggestion(*this, line);
452
0
}
453
454
0
void IOHandlerEditline::AutoCompleteCallback(CompletionRequest &request) {
455
0
  m_delegate.IOHandlerComplete(*this, request);
456
0
}
457
#endif
458
459
2.37k
const char *IOHandlerEditline::GetPrompt() {
460
2.37k
#if LLDB_ENABLE_LIBEDIT
461
2.37k
  if (m_editline_up) {
462
0
    return m_editline_up->GetPrompt();
463
2.37k
  } else {
464
2.37k
#endif
465
2.37k
    if (m_prompt.empty())
466
0
      return nullptr;
467
2.37k
#if LLDB_ENABLE_LIBEDIT
468
2.37k
  }
469
2.37k
#endif
470
2.37k
  return m_prompt.c_str();
471
2.37k
}
472
473
2.93k
bool IOHandlerEditline::SetPrompt(llvm::StringRef prompt) {
474
2.93k
  m_prompt = std::string(prompt);
475
476
2.93k
#if LLDB_ENABLE_LIBEDIT
477
2.93k
  if (m_editline_up)
478
9
    m_editline_up->SetPrompt(m_prompt.empty() ? 
nullptr0
: m_prompt.c_str());
479
2.93k
#endif
480
2.93k
  return true;
481
2.93k
}
482
483
0
const char *IOHandlerEditline::GetContinuationPrompt() {
484
0
  return (m_continuation_prompt.empty() ? nullptr
485
0
                                        : m_continuation_prompt.c_str());
486
0
}
487
488
1.45k
void IOHandlerEditline::SetContinuationPrompt(llvm::StringRef prompt) {
489
1.45k
  m_continuation_prompt = std::string(prompt);
490
491
1.45k
#if LLDB_ENABLE_LIBEDIT
492
1.45k
  if (m_editline_up)
493
9
    m_editline_up->SetContinuationPrompt(m_continuation_prompt.empty()
494
9
                                             ? nullptr
495
9
                                             : 
m_continuation_prompt.c_str()0
);
496
1.45k
#endif
497
1.45k
}
498
499
1.45k
void IOHandlerEditline::SetBaseLineNumber(uint32_t line) {
500
1.45k
  m_base_line_number = line;
501
1.45k
}
502
503
0
uint32_t IOHandlerEditline::GetCurrentLineIndex() const {
504
0
#if LLDB_ENABLE_LIBEDIT
505
0
  if (m_editline_up)
506
0
    return m_editline_up->GetCurrentLine();
507
0
#endif
508
0
  return m_curr_line_idx;
509
0
}
510
511
0
StringList IOHandlerEditline::GetCurrentLines() const {
512
0
#if LLDB_ENABLE_LIBEDIT
513
0
  if (m_editline_up)
514
0
    return m_editline_up->GetInputAsStringList();
515
0
#endif
516
  // When libedit is not used, the current lines can be gotten from
517
  // `m_current_lines_ptr`, which is updated whenever a new line is processed.
518
  // This doesn't happen when libedit is used, in which case
519
  // `m_current_lines_ptr` is only updated when the full input is terminated.
520
521
0
  if (m_current_lines_ptr)
522
0
    return *m_current_lines_ptr;
523
0
  return StringList();
524
0
}
525
526
7
bool IOHandlerEditline::GetLines(StringList &lines, bool &interrupted) {
527
7
  m_current_lines_ptr = &lines;
528
529
7
  bool success = false;
530
7
#if LLDB_ENABLE_LIBEDIT
531
7
  if (m_editline_up) {
532
1
    return m_editline_up->GetLines(m_base_line_number, lines, interrupted);
533
6
  } else {
534
6
#endif
535
6
    bool done = false;
536
6
    Status error;
537
538
23
    while (!done) {
539
      // Show line numbers if we are asked to
540
17
      std::string line;
541
17
      if (m_base_line_number > 0 && 
GetIsInteractive()3
) {
542
0
        if (m_output_sp) {
543
0
          m_output_sp->Printf("%u%s",
544
0
                              m_base_line_number + (uint32_t)lines.GetSize(),
545
0
                              GetPrompt() == nullptr ? " " : "");
546
0
        }
547
0
      }
548
549
17
      m_curr_line_idx = lines.GetSize();
550
551
17
      bool interrupted = false;
552
17
      if (GetLine(line, interrupted) && !interrupted) {
553
17
        lines.AppendString(line);
554
17
        done = m_delegate.IOHandlerIsInputComplete(*this, lines);
555
17
      } else {
556
0
        done = true;
557
0
      }
558
17
    }
559
6
    success = lines.GetSize() > 0;
560
6
#if LLDB_ENABLE_LIBEDIT
561
6
  }
562
6
#endif
563
6
  return success;
564
7
}
565
566
// Each IOHandler gets to run until it is done. It should read data from the
567
// "in" and place output into "out" and "err and return when done.
568
1.46k
void IOHandlerEditline::Run() {
569
1.46k
  std::string line;
570
10.2k
  while (IsActive()) {
571
8.81k
    bool interrupted = false;
572
8.81k
    if (m_multi_line) {
573
7
      StringList lines;
574
7
      if (GetLines(lines, interrupted)) {
575
7
        if (interrupted) {
576
0
          m_done = m_interrupt_exits;
577
0
          m_delegate.IOHandlerInputInterrupted(*this, line);
578
579
7
        } else {
580
7
          line = lines.CopyList();
581
7
          m_delegate.IOHandlerInputComplete(*this, line);
582
7
        }
583
7
      } else {
584
0
        m_done = true;
585
0
      }
586
8.80k
    } else {
587
8.80k
      if (GetLine(line, interrupted)) {
588
7.51k
        if (interrupted)
589
5
          m_delegate.IOHandlerInputInterrupted(*this, line);
590
7.51k
        else
591
7.51k
          m_delegate.IOHandlerInputComplete(*this, line);
592
7.51k
      } else {
593
1.28k
        m_done = true;
594
1.28k
      }
595
8.80k
    }
596
8.81k
  }
597
1.46k
}
598
599
2.46k
void IOHandlerEditline::Cancel() {
600
2.46k
#if LLDB_ENABLE_LIBEDIT
601
2.46k
  if (m_editline_up)
602
14
    m_editline_up->Cancel();
603
2.46k
#endif
604
2.46k
}
605
606
0
bool IOHandlerEditline::Interrupt() {
607
  // Let the delgate handle it first
608
0
  if (m_delegate.IOHandlerInterrupt(*this))
609
0
    return true;
610
611
0
#if LLDB_ENABLE_LIBEDIT
612
0
  if (m_editline_up)
613
0
    return m_editline_up->Interrupt();
614
0
#endif
615
0
  return false;
616
0
}
617
618
0
void IOHandlerEditline::GotEOF() {
619
0
#if LLDB_ENABLE_LIBEDIT
620
0
  if (m_editline_up)
621
0
    m_editline_up->Interrupt();
622
0
#endif
623
0
}
624
625
2.25k
void IOHandlerEditline::PrintAsync(const char *s, size_t len, bool is_stdout) {
626
2.25k
#if LLDB_ENABLE_LIBEDIT
627
2.25k
  if (m_editline_up) {
628
340
    std::lock_guard<std::recursive_mutex> guard(m_output_mutex);
629
340
    lldb::StreamFileSP stream = is_stdout ? m_output_sp : 
m_error_sp0
;
630
340
    m_editline_up->PrintAsync(stream.get(), s, len);
631
340
  } else
632
1.91k
#endif
633
1.91k
  {
634
#ifdef _WIN32
635
    const char *prompt = GetPrompt();
636
    if (prompt) {
637
      // Back up over previous prompt using Windows API
638
      CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
639
      HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
640
      GetConsoleScreenBufferInfo(console_handle, &screen_buffer_info);
641
      COORD coord = screen_buffer_info.dwCursorPosition;
642
      coord.X -= strlen(prompt);
643
      if (coord.X < 0)
644
        coord.X = 0;
645
      SetConsoleCursorPosition(console_handle, coord);
646
    }
647
#endif
648
1.91k
    IOHandler::PrintAsync(s, len, is_stdout);
649
#ifdef _WIN32
650
    if (prompt)
651
      IOHandler::PrintAsync(prompt, strlen(prompt), is_stdout);
652
#endif
653
1.91k
  }
654
2.25k
}