1 //===-- InputReader.cpp -----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/lldb-python.h"
14 #include "lldb/Core/InputReader.h"
15 #include "lldb/Core/Debugger.h"
16 #include "lldb/Interpreter/CommandInterpreter.h"
19 using namespace lldb_private;
21 InputReader::InputReader (Debugger &debugger) :
22 m_debugger (debugger),
24 m_callback_baton (NULL),
26 m_granularity (eInputReaderGranularityInvalid),
30 m_reader_done (false),
32 m_save_user_input(false)
36 InputReader::~InputReader ()
41 InputReader::Initialize
45 lldb::InputReaderGranularity granularity,
46 const char *end_token,
52 m_callback = callback;
53 m_callback_baton = baton,
54 m_granularity = granularity;
55 if (end_token != NULL)
56 m_end_token = end_token;
62 if (m_granularity == eInputReaderGranularityInvalid)
64 err.SetErrorString ("Invalid read token size: Reader must be initialized with a token size other than 'eInputReaderGranularityInvalid'.");
67 if (end_token != NULL && granularity != eInputReaderGranularityInvalid)
69 if (granularity == eInputReaderGranularityByte)
71 // Check to see if end_token is longer than one byte.
73 if (strlen (end_token) > 1)
75 err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (byte).");
78 else if (granularity == eInputReaderGranularityWord)
80 // Check to see if m_end_token contains any white space (i.e. is multiple words).
82 const char *white_space = " \t\n";
83 size_t pos = m_end_token.find_first_of (white_space);
84 if (pos != std::string::npos)
86 err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (word).");
91 // Check to see if m_end_token contains any newlines; cannot handle multi-line end tokens.
93 size_t pos = m_end_token.find_first_of ('\n');
94 if (pos != std::string::npos)
96 err.SetErrorString ("Invalid end token: End token cannot contain a newline.");
107 InputReader::HandleRawBytes (const char *bytes, size_t bytes_len)
109 const char *end_token = NULL;
111 if (m_end_token.empty() == false)
113 end_token = ::strstr (bytes, m_end_token.c_str());
114 if (end_token >= bytes + bytes_len)
118 const char *p = bytes;
119 const char *end = bytes + bytes_len;
121 switch (m_granularity)
123 case eInputReaderGranularityInvalid:
126 case eInputReaderGranularityByte:
131 p += m_end_token.size();
136 if (m_callback (m_callback_baton, *this, eInputReaderGotToken, p, 1) == 0)
142 // Return how many bytes were handled.
147 case eInputReaderGranularityWord:
150 const char *word_start = NULL;
151 bool send_word = false;
152 for (; p < end; ++p, send_word = false)
154 if (end_token && end_token == p)
162 if (isspace(ch) && (!quote || (quote == ch && p[-1] != '\\')))
164 // We have a space character or the terminating quote
165 send_word = word_start != NULL;
170 // We are in the middle of a quoted character
173 else if (ch == '"' || ch == '\'' || ch == '`')
175 else if (word_start == NULL)
177 // We have the first character in a word
183 const size_t word_len = p - word_start;
184 size_t bytes_handled = m_callback (m_callback_baton,
186 eInputReaderGotToken,
190 if (bytes_handled != word_len)
191 return word_start - bytes + bytes_handled;
201 case eInputReaderGranularityLine:
203 const char *line_start = bytes;
204 const char *end_line = NULL;
208 if (ch == '\n' || ch == '\r')
210 size_t line_length = p - line_start;
211 // Now skip the newline character
213 // Skip a complete DOS newline if we run into one
214 if (ch == 0xd && p < end && *p == 0xa)
217 if (line_start <= end_token && end_token < line_start + line_length)
220 m_callback (m_callback_baton,
222 eInputReaderGotToken,
224 end_token - line_start);
229 size_t bytes_handled = m_callback (m_callback_baton,
231 eInputReaderGotToken,
237 if (bytes_handled != line_length)
239 // The input reader wasn't able to handle all the data
240 return line_start - bytes + bytes_handled;
256 return end_line - bytes;
261 case eInputReaderGranularityAll:
263 // Nothing should be handle unless we see our end token
266 size_t length = end_token - bytes;
267 size_t bytes_handled = m_callback (m_callback_baton,
269 eInputReaderGotToken,
274 p += bytes_handled + m_end_token.size();
276 // Consume any white space, such as newlines, beyond the end token
278 while (p < end && isspace(*p))
281 if (bytes_handled != length)
282 return bytes_handled;
286 //return bytes_handled + m_end_token.size();
297 InputReader::GetPrompt () const
299 if (!m_prompt.empty())
300 return m_prompt.c_str();
306 InputReader::RefreshPrompt ()
308 if (m_debugger.GetCommandInterpreter().GetBatchCommandMode())
311 if (!m_prompt.empty())
313 File &out_file = m_debugger.GetOutputFile();
314 if (out_file.IsValid())
316 out_file.Printf ("%s", m_prompt.c_str());
323 InputReader::Notify (InputReaderAction notification)
325 switch (notification)
327 case eInputReaderActivate:
328 case eInputReaderReactivate:
330 m_reader_done.SetValue(false, eBroadcastAlways);
333 case eInputReaderDeactivate:
334 case eInputReaderDone:
338 case eInputReaderAsynchronousOutputWritten:
341 case eInputReaderInterrupt:
342 case eInputReaderEndOfFile:
345 case eInputReaderGotToken:
346 return; // We don't notify the tokens here, it is done in HandleRawBytes
349 m_callback (m_callback_baton, *this, notification, NULL, 0);
350 if (notification == eInputReaderDone)
351 m_reader_done.SetValue(true, eBroadcastAlways);
355 InputReader::WaitOnReaderIsDone ()
357 m_reader_done.WaitForValueEqualTo (true);
361 InputReader::GranularityAsCString (lldb::InputReaderGranularity granularity)
365 case eInputReaderGranularityInvalid: return "invalid";
366 case eInputReaderGranularityByte: return "byte";
367 case eInputReaderGranularityWord: return "word";
368 case eInputReaderGranularityLine: return "line";
369 case eInputReaderGranularityAll: return "all";
372 static char unknown_state_string[64];
373 snprintf(unknown_state_string, sizeof (unknown_state_string), "InputReaderGranularity = %i", granularity);
374 return unknown_state_string;
378 InputReader::HandlerData::GetBatchMode()
380 return reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
384 InputReader::HandlerData::GetOutStream()
386 return reader.GetDebugger().GetAsyncOutputStream();