aboutsummaryrefslogtreecommitdiff
path: root/source/Core/InputReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Core/InputReader.cpp')
-rw-r--r--source/Core/InputReader.cpp387
1 files changed, 387 insertions, 0 deletions
diff --git a/source/Core/InputReader.cpp b/source/Core/InputReader.cpp
new file mode 100644
index 000000000000..cbaa671bcba5
--- /dev/null
+++ b/source/Core/InputReader.cpp
@@ -0,0 +1,387 @@
+//===-- InputReader.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include <string>
+
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+InputReader::InputReader (Debugger &debugger) :
+ m_debugger (debugger),
+ m_callback (NULL),
+ m_callback_baton (NULL),
+ m_end_token (),
+ m_granularity (eInputReaderGranularityInvalid),
+ m_done (true),
+ m_echo (true),
+ m_active (false),
+ m_reader_done (false),
+ m_user_input(),
+ m_save_user_input(false)
+{
+}
+
+InputReader::~InputReader ()
+{
+}
+
+Error
+InputReader::Initialize
+(
+ Callback callback,
+ void *baton,
+ lldb::InputReaderGranularity granularity,
+ const char *end_token,
+ const char *prompt,
+ bool echo
+)
+{
+ Error err;
+ m_callback = callback;
+ m_callback_baton = baton,
+ m_granularity = granularity;
+ if (end_token != NULL)
+ m_end_token = end_token;
+ if (prompt != NULL)
+ m_prompt = prompt;
+ m_done = true;
+ m_echo = echo;
+
+ if (m_granularity == eInputReaderGranularityInvalid)
+ {
+ err.SetErrorString ("Invalid read token size: Reader must be initialized with a token size other than 'eInputReaderGranularityInvalid'.");
+ }
+ else
+ if (end_token != NULL && granularity != eInputReaderGranularityInvalid)
+ {
+ if (granularity == eInputReaderGranularityByte)
+ {
+ // Check to see if end_token is longer than one byte.
+
+ if (strlen (end_token) > 1)
+ {
+ err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (byte).");
+ }
+ }
+ else if (granularity == eInputReaderGranularityWord)
+ {
+ // Check to see if m_end_token contains any white space (i.e. is multiple words).
+
+ const char *white_space = " \t\n";
+ size_t pos = m_end_token.find_first_of (white_space);
+ if (pos != std::string::npos)
+ {
+ err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (word).");
+ }
+ }
+ else
+ {
+ // Check to see if m_end_token contains any newlines; cannot handle multi-line end tokens.
+
+ size_t pos = m_end_token.find_first_of ('\n');
+ if (pos != std::string::npos)
+ {
+ err.SetErrorString ("Invalid end token: End token cannot contain a newline.");
+ }
+ }
+ }
+
+ m_done = err.Fail();
+
+ return err;
+}
+
+size_t
+InputReader::HandleRawBytes (const char *bytes, size_t bytes_len)
+{
+ const char *end_token = NULL;
+
+ if (m_end_token.empty() == false)
+ {
+ end_token = ::strstr (bytes, m_end_token.c_str());
+ if (end_token >= bytes + bytes_len)
+ end_token = NULL;
+ }
+
+ const char *p = bytes;
+ const char *end = bytes + bytes_len;
+
+ switch (m_granularity)
+ {
+ case eInputReaderGranularityInvalid:
+ break;
+
+ case eInputReaderGranularityByte:
+ while (p < end)
+ {
+ if (end_token == p)
+ {
+ p += m_end_token.size();
+ SetIsDone(true);
+ break;
+ }
+
+ if (m_callback (m_callback_baton, *this, eInputReaderGotToken, p, 1) == 0)
+ break;
+ ++p;
+ if (IsDone())
+ break;
+ }
+ // Return how many bytes were handled.
+ return p - bytes;
+ break;
+
+
+ case eInputReaderGranularityWord:
+ {
+ char quote = '\0';
+ const char *word_start = NULL;
+ bool send_word = false;
+ for (; p < end; ++p, send_word = false)
+ {
+ if (end_token && end_token == p)
+ {
+ m_end_token.size();
+ SetIsDone(true);
+ break;
+ }
+
+ const char ch = *p;
+ if (isspace(ch) && (!quote || (quote == ch && p[-1] != '\\')))
+ {
+ // We have a space character or the terminating quote
+ send_word = word_start != NULL;
+ quote = '\0';
+ }
+ else if (quote)
+ {
+ // We are in the middle of a quoted character
+ continue;
+ }
+ else if (ch == '"' || ch == '\'' || ch == '`')
+ quote = ch;
+ else if (word_start == NULL)
+ {
+ // We have the first character in a word
+ word_start = p;
+ }
+
+ if (send_word)
+ {
+ const size_t word_len = p - word_start;
+ size_t bytes_handled = m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ word_start,
+ word_len);
+
+ if (bytes_handled != word_len)
+ return word_start - bytes + bytes_handled;
+
+ if (IsDone())
+ return p - bytes;
+ }
+ }
+ }
+ break;
+
+
+ case eInputReaderGranularityLine:
+ {
+ const char *line_start = bytes;
+ const char *end_line = NULL;
+ while (p < end)
+ {
+ const char ch = *p;
+ if (ch == '\n' || ch == '\r')
+ {
+ size_t line_length = p - line_start;
+ // Now skip the newline character
+ ++p;
+ // Skip a complete DOS newline if we run into one
+ if (ch == 0xd && p < end && *p == 0xa)
+ ++p;
+
+ if (line_start <= end_token && end_token < line_start + line_length)
+ {
+ SetIsDone(true);
+ m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ line_start,
+ end_token - line_start);
+
+ return p - bytes;
+ }
+
+ size_t bytes_handled = m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ line_start,
+ line_length);
+
+ end_line = p;
+
+ if (bytes_handled != line_length)
+ {
+ // The input reader wasn't able to handle all the data
+ return line_start - bytes + bytes_handled;
+ }
+
+
+ if (IsDone())
+ return p - bytes;
+
+ line_start = p;
+ }
+ else
+ {
+ ++p;
+ }
+ }
+
+ if (end_line)
+ return end_line - bytes;
+ }
+ break;
+
+
+ case eInputReaderGranularityAll:
+ {
+ // Nothing should be handle unless we see our end token
+ if (end_token)
+ {
+ size_t length = end_token - bytes;
+ size_t bytes_handled = m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ bytes,
+ length);
+ m_done = true;
+
+ p += bytes_handled + m_end_token.size();
+
+ // Consume any white space, such as newlines, beyond the end token
+
+ while (p < end && isspace(*p))
+ ++p;
+
+ if (bytes_handled != length)
+ return bytes_handled;
+ else
+ {
+ return p - bytes;
+ //return bytes_handled + m_end_token.size();
+ }
+ }
+ return 0;
+ }
+ break;
+ }
+ return 0;
+}
+
+const char *
+InputReader::GetPrompt () const
+{
+ if (!m_prompt.empty())
+ return m_prompt.c_str();
+ else
+ return NULL;
+}
+
+void
+InputReader::RefreshPrompt ()
+{
+ if (m_debugger.GetCommandInterpreter().GetBatchCommandMode())
+ return;
+
+ if (!m_prompt.empty())
+ {
+ File &out_file = m_debugger.GetOutputFile();
+ if (out_file.IsValid())
+ {
+ out_file.Printf ("%s", m_prompt.c_str());
+ out_file.Flush();
+ }
+ }
+}
+
+void
+InputReader::Notify (InputReaderAction notification)
+{
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ case eInputReaderReactivate:
+ m_active = true;
+ m_reader_done.SetValue(false, eBroadcastAlways);
+ break;
+
+ case eInputReaderDeactivate:
+ case eInputReaderDone:
+ m_active = false;
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderInterrupt:
+ case eInputReaderEndOfFile:
+ break;
+
+ case eInputReaderGotToken:
+ return; // We don't notify the tokens here, it is done in HandleRawBytes
+ }
+ if (m_callback)
+ m_callback (m_callback_baton, *this, notification, NULL, 0);
+ if (notification == eInputReaderDone)
+ m_reader_done.SetValue(true, eBroadcastAlways);
+}
+
+void
+InputReader::WaitOnReaderIsDone ()
+{
+ m_reader_done.WaitForValueEqualTo (true);
+}
+
+const char *
+InputReader::GranularityAsCString (lldb::InputReaderGranularity granularity)
+{
+ switch (granularity)
+ {
+ case eInputReaderGranularityInvalid: return "invalid";
+ case eInputReaderGranularityByte: return "byte";
+ case eInputReaderGranularityWord: return "word";
+ case eInputReaderGranularityLine: return "line";
+ case eInputReaderGranularityAll: return "all";
+ }
+
+ static char unknown_state_string[64];
+ snprintf(unknown_state_string, sizeof (unknown_state_string), "InputReaderGranularity = %i", granularity);
+ return unknown_state_string;
+}
+
+bool
+InputReader::HandlerData::GetBatchMode()
+{
+ return reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+}
+
+lldb::StreamSP
+InputReader::HandlerData::GetOutStream()
+{
+ return reader.GetDebugger().GetAsyncOutputStream();
+}