Files
llvm-project/lldb/source/Core/InputReader.cpp
Enrico Granata f2bbf717f7 Python summary strings:
- you can use a Python script to write a summary string for data-types, in one of
   three ways:
    -P option and typing the script a line at a time
    -s option and passing a one-line Python script
    -F option and passing the name of a Python function
   these options all work for the "type summary add" command
   your Python code (if provided through -P or -s) is wrapped in a function
   that accepts two parameters: valobj (a ValueObject) and dict (an LLDB
   internal dictionary object). if you use -F and give a function name,
   you're expected to define the function on your own and with the right
   prototype. your function, however defined, must return a Python string
 - test case for the Python summary feature
 - a few quirks:
  Python summaries cannot have names, and cannot use regex as type names
  both issues will be fixed ASAP
major redesign of type summary code:
 - type summary working with strings and type summary working with Python code
   are two classes, with a common base class SummaryFormat
 - SummaryFormat classes now are able to actively format objects rather than
   just aggregating data
 - cleaner code to print descriptions for summaries
the public API now exports a method to easily navigate a ValueObject hierarchy
New InputReaderEZ and PriorityPointerPair classes
Several minor fixes and improvements

llvm-svn: 135238
2011-07-15 02:26:42 +00:00

383 lines
11 KiB
C++

//===-- 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 <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)
{
}
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)
{
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();
}