Coverage Report

Created: 2022-01-18 06:27

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