blob: cbaa671bcba5265eb0c6cda04749be2cdbab7093 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- InputReader.cpp -----------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Daniel Malead891f9b2012-12-05 00:20:57 +000010#include "lldb/lldb-python.h"
11
Chris Lattner24943d22010-06-08 16:52:24 +000012#include <string>
13
14#include "lldb/Core/InputReader.h"
15#include "lldb/Core/Debugger.h"
Caroline Tice892fadd2011-06-16 16:27:19 +000016#include "lldb/Interpreter/CommandInterpreter.h"
Chris Lattner24943d22010-06-08 16:52:24 +000017
18using namespace lldb;
19using namespace lldb_private;
20
Greg Clayton63094e02010-06-23 01:19:29 +000021InputReader::InputReader (Debugger &debugger) :
22 m_debugger (debugger),
Chris Lattner24943d22010-06-08 16:52:24 +000023 m_callback (NULL),
24 m_callback_baton (NULL),
25 m_end_token (),
26 m_granularity (eInputReaderGranularityInvalid),
27 m_done (true),
28 m_echo (true),
Jim Ingham5e16ef52010-10-04 19:49:29 +000029 m_active (false),
Enrico Granatae89ab7b2011-07-25 16:59:05 +000030 m_reader_done (false),
31 m_user_input(),
32 m_save_user_input(false)
Chris Lattner24943d22010-06-08 16:52:24 +000033{
34}
35
36InputReader::~InputReader ()
37{
38}
39
40Error
41InputReader::Initialize
42(
43 Callback callback,
44 void *baton,
45 lldb::InputReaderGranularity granularity,
46 const char *end_token,
47 const char *prompt,
48 bool echo
49)
50{
51 Error err;
52 m_callback = callback;
53 m_callback_baton = baton,
54 m_granularity = granularity;
55 if (end_token != NULL)
56 m_end_token = end_token;
57 if (prompt != NULL)
58 m_prompt = prompt;
59 m_done = true;
60 m_echo = echo;
61
62 if (m_granularity == eInputReaderGranularityInvalid)
63 {
64 err.SetErrorString ("Invalid read token size: Reader must be initialized with a token size other than 'eInputReaderGranularityInvalid'.");
65 }
66 else
67 if (end_token != NULL && granularity != eInputReaderGranularityInvalid)
68 {
69 if (granularity == eInputReaderGranularityByte)
70 {
71 // Check to see if end_token is longer than one byte.
72
73 if (strlen (end_token) > 1)
74 {
75 err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (byte).");
76 }
77 }
78 else if (granularity == eInputReaderGranularityWord)
79 {
80 // Check to see if m_end_token contains any white space (i.e. is multiple words).
81
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)
85 {
86 err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (word).");
87 }
88 }
89 else
90 {
91 // Check to see if m_end_token contains any newlines; cannot handle multi-line end tokens.
92
93 size_t pos = m_end_token.find_first_of ('\n');
94 if (pos != std::string::npos)
95 {
96 err.SetErrorString ("Invalid end token: End token cannot contain a newline.");
97 }
98 }
99 }
100
101 m_done = err.Fail();
102
103 return err;
104}
105
106size_t
107InputReader::HandleRawBytes (const char *bytes, size_t bytes_len)
108{
109 const char *end_token = NULL;
110
111 if (m_end_token.empty() == false)
112 {
113 end_token = ::strstr (bytes, m_end_token.c_str());
114 if (end_token >= bytes + bytes_len)
115 end_token = NULL;
116 }
117
118 const char *p = bytes;
119 const char *end = bytes + bytes_len;
120
121 switch (m_granularity)
122 {
123 case eInputReaderGranularityInvalid:
124 break;
125
126 case eInputReaderGranularityByte:
127 while (p < end)
128 {
129 if (end_token == p)
130 {
131 p += m_end_token.size();
132 SetIsDone(true);
133 break;
134 }
135
Greg Clayton63094e02010-06-23 01:19:29 +0000136 if (m_callback (m_callback_baton, *this, eInputReaderGotToken, p, 1) == 0)
Chris Lattner24943d22010-06-08 16:52:24 +0000137 break;
138 ++p;
139 if (IsDone())
140 break;
141 }
142 // Return how many bytes were handled.
143 return p - bytes;
144 break;
145
146
147 case eInputReaderGranularityWord:
148 {
149 char quote = '\0';
150 const char *word_start = NULL;
151 bool send_word = false;
152 for (; p < end; ++p, send_word = false)
153 {
154 if (end_token && end_token == p)
155 {
Greg Clayton4a379b12012-07-17 03:23:13 +0000156 m_end_token.size();
Chris Lattner24943d22010-06-08 16:52:24 +0000157 SetIsDone(true);
158 break;
159 }
160
161 const char ch = *p;
162 if (isspace(ch) && (!quote || (quote == ch && p[-1] != '\\')))
163 {
164 // We have a space character or the terminating quote
165 send_word = word_start != NULL;
166 quote = '\0';
167 }
168 else if (quote)
169 {
170 // We are in the middle of a quoted character
171 continue;
172 }
173 else if (ch == '"' || ch == '\'' || ch == '`')
174 quote = ch;
175 else if (word_start == NULL)
176 {
177 // We have the first character in a word
178 word_start = p;
179 }
180
181 if (send_word)
182 {
183 const size_t word_len = p - word_start;
184 size_t bytes_handled = m_callback (m_callback_baton,
Greg Clayton63094e02010-06-23 01:19:29 +0000185 *this,
Chris Lattner24943d22010-06-08 16:52:24 +0000186 eInputReaderGotToken,
187 word_start,
188 word_len);
189
190 if (bytes_handled != word_len)
191 return word_start - bytes + bytes_handled;
192
193 if (IsDone())
194 return p - bytes;
195 }
196 }
197 }
198 break;
199
200
201 case eInputReaderGranularityLine:
202 {
203 const char *line_start = bytes;
204 const char *end_line = NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000205 while (p < end)
206 {
207 const char ch = *p;
208 if (ch == '\n' || ch == '\r')
209 {
210 size_t line_length = p - line_start;
211 // Now skip the newline character
212 ++p;
213 // Skip a complete DOS newline if we run into one
214 if (ch == 0xd && p < end && *p == 0xa)
215 ++p;
216
217 if (line_start <= end_token && end_token < line_start + line_length)
218 {
219 SetIsDone(true);
220 m_callback (m_callback_baton,
Greg Clayton63094e02010-06-23 01:19:29 +0000221 *this,
Chris Lattner24943d22010-06-08 16:52:24 +0000222 eInputReaderGotToken,
223 line_start,
224 end_token - line_start);
225
226 return p - bytes;
227 }
228
229 size_t bytes_handled = m_callback (m_callback_baton,
Greg Clayton63094e02010-06-23 01:19:29 +0000230 *this,
Chris Lattner24943d22010-06-08 16:52:24 +0000231 eInputReaderGotToken,
232 line_start,
233 line_length);
234
235 end_line = p;
236
237 if (bytes_handled != line_length)
238 {
239 // The input reader wasn't able to handle all the data
240 return line_start - bytes + bytes_handled;
241 }
242
243
244 if (IsDone())
245 return p - bytes;
246
247 line_start = p;
248 }
249 else
250 {
251 ++p;
252 }
253 }
254
255 if (end_line)
256 return end_line - bytes;
257 }
258 break;
259
260
261 case eInputReaderGranularityAll:
262 {
263 // Nothing should be handle unless we see our end token
264 if (end_token)
265 {
266 size_t length = end_token - bytes;
267 size_t bytes_handled = m_callback (m_callback_baton,
Greg Clayton63094e02010-06-23 01:19:29 +0000268 *this,
Chris Lattner24943d22010-06-08 16:52:24 +0000269 eInputReaderGotToken,
270 bytes,
271 length);
272 m_done = true;
273
274 p += bytes_handled + m_end_token.size();
275
276 // Consume any white space, such as newlines, beyond the end token
277
278 while (p < end && isspace(*p))
279 ++p;
280
281 if (bytes_handled != length)
282 return bytes_handled;
283 else
284 {
285 return p - bytes;
286 //return bytes_handled + m_end_token.size();
287 }
288 }
289 return 0;
290 }
291 break;
292 }
293 return 0;
294}
295
Chris Lattner24943d22010-06-08 16:52:24 +0000296const char *
297InputReader::GetPrompt () const
298{
299 if (!m_prompt.empty())
300 return m_prompt.c_str();
301 else
302 return NULL;
303}
304
305void
306InputReader::RefreshPrompt ()
307{
Caroline Tice892fadd2011-06-16 16:27:19 +0000308 if (m_debugger.GetCommandInterpreter().GetBatchCommandMode())
309 return;
310
Chris Lattner24943d22010-06-08 16:52:24 +0000311 if (!m_prompt.empty())
312 {
Greg Clayton58928562011-02-09 01:08:52 +0000313 File &out_file = m_debugger.GetOutputFile();
314 if (out_file.IsValid())
315 {
316 out_file.Printf ("%s", m_prompt.c_str());
317 out_file.Flush();
318 }
Chris Lattner24943d22010-06-08 16:52:24 +0000319 }
320}
321
322void
323InputReader::Notify (InputReaderAction notification)
324{
325 switch (notification)
326 {
327 case eInputReaderActivate:
328 case eInputReaderReactivate:
329 m_active = true;
Jim Ingham5e16ef52010-10-04 19:49:29 +0000330 m_reader_done.SetValue(false, eBroadcastAlways);
Chris Lattner24943d22010-06-08 16:52:24 +0000331 break;
332
333 case eInputReaderDeactivate:
334 case eInputReaderDone:
335 m_active = false;
336 break;
337
Caroline Tice4a348082011-05-02 20:41:46 +0000338 case eInputReaderAsynchronousOutputWritten:
339 break;
340
Caroline Ticec4f55fe2010-11-19 20:47:54 +0000341 case eInputReaderInterrupt:
342 case eInputReaderEndOfFile:
343 break;
344
Chris Lattner24943d22010-06-08 16:52:24 +0000345 case eInputReaderGotToken:
346 return; // We don't notify the tokens here, it is done in HandleRawBytes
347 }
348 if (m_callback)
Greg Clayton63094e02010-06-23 01:19:29 +0000349 m_callback (m_callback_baton, *this, notification, NULL, 0);
Jim Ingham5e16ef52010-10-04 19:49:29 +0000350 if (notification == eInputReaderDone)
351 m_reader_done.SetValue(true, eBroadcastAlways);
352}
353
354void
355InputReader::WaitOnReaderIsDone ()
356{
357 m_reader_done.WaitForValueEqualTo (true);
Chris Lattner24943d22010-06-08 16:52:24 +0000358}
Caroline Tice7826c882010-10-26 03:11:13 +0000359
360const char *
361InputReader::GranularityAsCString (lldb::InputReaderGranularity granularity)
362{
363 switch (granularity)
364 {
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";
370 }
371
372 static char unknown_state_string[64];
373 snprintf(unknown_state_string, sizeof (unknown_state_string), "InputReaderGranularity = %i", granularity);
374 return unknown_state_string;
375}
376
Enrico Granataf7a9b142011-07-15 02:26:42 +0000377bool
378InputReader::HandlerData::GetBatchMode()
379{
380 return reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
381}
382
383lldb::StreamSP
384InputReader::HandlerData::GetOutStream()
385{
386 return reader.GetDebugger().GetAsyncOutputStream();
Greg Clayton153ccd72011-08-10 02:10:13 +0000387}