Don't limit StreamTee to just two streams. It now can contain

N streams by making the stream a vector of stream shared pointers
that is protected by a mutex. Streams can be get/set by index which
allows indexes to be defined as stream indentifiers. If a stream is
set at index 3 and there are now streams in the collection, then
empty stream objects are inserted to ensure that stream at index 3
has a valid stream. There is also an append method that allows a stream
to be pushed onto the stack. This will allow our streams to be very
flexible in where the output goes.

Modified the CommandReturnObject to use the new StreamTee functionality.
This class now defines two StreamTee indexes: 0 for the stream string
stream, and 1 for the immediate stream. This is used both on the output
and error streams.

Added the ability to get argument types as strings or as descriptions.
This is exported through the SBCommandInterpreter API to allow external
access.

Modified the Driver class to use the newly exported argument names from
SBCommandInterpreter::GetArgumentTypeAsCString().

llvm-svn: 126067
This commit is contained in:
Greg Clayton 2011-02-20 02:15:07 +00:00
parent 6d90e8937c
commit 9d0402b1eb
9 changed files with 248 additions and 150 deletions

View File

@ -33,6 +33,12 @@ public:
~SBCommandInterpreter ();
static const char *
GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type);
static const char *
GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type);
bool
IsValid() const;

View File

@ -11,6 +11,7 @@
#define liblldb_StreamTee_h_
#include "lldb/Core/Stream.h"
#include "lldb/Host/Mutex.h"
namespace lldb_private {
@ -18,20 +19,42 @@ class StreamTee : public Stream
{
public:
StreamTee () :
Stream()
Stream (),
m_streams_mutex (Mutex::eMutexTypeRecursive),
m_streams ()
{
}
StreamTee (lldb::StreamSP &stream_1_sp, lldb::StreamSP &stream_2_sp):
m_stream_1_sp (stream_1_sp),
m_stream_2_sp (stream_2_sp)
StreamTee (lldb::StreamSP &stream_sp):
Stream (),
m_streams_mutex (Mutex::eMutexTypeRecursive),
m_streams ()
{
// No need to lock mutex during construction
if (stream_sp)
m_streams.push_back (stream_sp);
}
StreamTee (lldb::StreamSP &stream_1_sp):
m_stream_1_sp (stream_1_sp),
m_stream_2_sp ()
StreamTee (lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp) :
Stream (),
m_streams_mutex (Mutex::eMutexTypeRecursive),
m_streams ()
{
// No need to lock mutex during construction
if (stream_sp)
m_streams.push_back (stream_sp);
if (stream_2_sp)
m_streams.push_back (stream_2_sp);
}
StreamTee (const StreamTee &rhs) :
Stream (rhs),
m_streams_mutex (Mutex::eMutexTypeRecursive),
m_streams() // Don't copy until we lock down "rhs"
{
Mutex::Locker locker (rhs.m_streams_mutex);
m_streams = rhs.m_streams;
}
virtual
@ -39,58 +62,109 @@ public:
{
}
StreamTee &
operator = (const StreamTee &rhs)
{
if (this != &rhs) {
Stream::operator=(rhs);
Mutex::Locker lhs_locker (m_streams_mutex);
Mutex::Locker rhs_locker (rhs.m_streams_mutex);
m_streams = rhs.m_streams;
}
return *this;
}
virtual void
Flush ()
{
if (m_stream_1_sp)
m_stream_1_sp->Flush ();
if (m_stream_2_sp)
m_stream_2_sp->Flush ();
Mutex::Locker locker (m_streams_mutex);
collection::iterator pos, end;
for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos)
{
// Allow for our collection to contain NULL streams. This allows
// the StreamTee to be used with hard coded indexes for clients
// that might want N total streams with only a few that are set
// to valid values.
Stream *strm = pos->get();
if (strm)
strm->Flush ();
}
}
virtual int
Write (const void *s, size_t length)
{
int ret_1;
int ret_2;
if (m_stream_1_sp)
ret_1 = m_stream_1_sp->Write (s, length);
if (m_stream_2_sp)
ret_2 = m_stream_2_sp->Write (s, length);
return ret_1 < ret_2 ? ret_1 : ret_2;
Mutex::Locker locker (m_streams_mutex);
if (m_streams.empty())
return 0;
int min_bytes_written = INT_MAX;
collection::iterator pos, end;
for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos)
{
// Allow for our collection to contain NULL streams. This allows
// the StreamTee to be used with hard coded indexes for clients
// that might want N total streams with only a few that are set
// to valid values.
Stream *strm = pos->get();
if (strm)
{
int bytes_written = strm->Write (s, length);
if (min_bytes_written > bytes_written)
min_bytes_written = bytes_written;
}
}
return min_bytes_written;
}
size_t
AppendStream (const lldb::StreamSP &stream_sp)
{
size_t new_idx = m_streams.size();
Mutex::Locker locker (m_streams_mutex);
m_streams.push_back (stream_sp);
return new_idx;
}
size_t
GetNumStreams () const
{
size_t result = 0;
{
Mutex::Locker locker (m_streams_mutex);
result = m_streams.size();
}
return result;
}
lldb::StreamSP
GetStreamAtIndex (uint32_t idx)
{
lldb::StreamSP stream_sp;
Mutex::Locker locker (m_streams_mutex);
if (idx < m_streams.size())
stream_sp = m_streams[idx];
return stream_sp;
}
void
SetStream1 (lldb::StreamSP &stream_1_sp)
SetStreamAtIndex (uint32_t idx, const lldb::StreamSP& stream_sp)
{
m_stream_1_sp = stream_1_sp;
}
void
SetStream2 (lldb::StreamSP &stream_2_sp)
{
m_stream_2_sp = stream_2_sp;
}
lldb::StreamSP &
GetStream1 ()
{
return m_stream_1_sp;
}
lldb::StreamSP &
GetStream2 ()
{
return m_stream_2_sp;
Mutex::Locker locker (m_streams_mutex);
// Resize our stream vector as necessary to fit as many streams
// as needed. This also allows this class to be used with hard
// coded indexes that can be used contain many streams, not all
// of which are valid.
if (idx >= m_streams.size())
m_streams.resize(idx + 1);
m_streams[idx] = stream_sp;
}
protected:
lldb::StreamSP m_stream_1_sp;
lldb::StreamSP m_stream_2_sp;
typedef std::vector<lldb::StreamSP> collection;
mutable Mutex m_streams_mutex;
collection m_streams;
};
} // namespace lldb_private

View File

@ -59,6 +59,13 @@ public:
virtual
~CommandObject ();
static const char *
GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type);
static const char *
GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type);
CommandInterpreter &
GetCommandInterpreter ()
{

View File

@ -34,17 +34,18 @@ public:
const char *
GetOutputData ()
{
if (m_output_stream_string_sp)
return static_cast<StreamString *>(m_output_stream_string_sp.get())->GetData();
else
return "";
lldb::StreamSP stream_sp (m_out_stream.GetStreamAtIndex (eStreamStringIndex));
if (stream_sp)
return static_cast<StreamString *>(stream_sp.get())->GetData();
return "";
}
const char *
GetErrorData ()
{
if (m_error_stream_string_sp)
return static_cast<StreamString *>(m_error_stream_string_sp.get())->GetData();
lldb::StreamSP stream_sp (m_err_stream.GetStreamAtIndex (eStreamStringIndex));
if (stream_sp)
return static_cast<StreamString *>(stream_sp.get())->GetData();
else
return "";
}
@ -52,63 +53,66 @@ public:
Stream &
GetOutputStream ()
{
if (!m_output_stream_string_sp)
// Make sure we at least have our normal string stream output stream
lldb::StreamSP stream_sp (m_out_stream.GetStreamAtIndex (eStreamStringIndex));
if (!stream_sp)
{
StreamString *new_stream = new StreamString();
m_output_stream_string_sp.reset (new_stream);
m_output_stream.SetStream1 (m_output_stream_string_sp);
stream_sp.reset (new StreamString());
m_out_stream.SetStreamAtIndex (eStreamStringIndex, stream_sp);
}
return m_output_stream;
return m_out_stream;
}
Stream &
GetErrorStream ()
{
if (!m_error_stream_string_sp)
// Make sure we at least have our normal string stream output stream
lldb::StreamSP stream_sp (m_err_stream.GetStreamAtIndex (eStreamStringIndex));
if (!stream_sp)
{
StreamString *new_stream = new StreamString();
m_error_stream_string_sp.reset (new_stream);
m_error_stream.SetStream1 (m_error_stream_string_sp);
stream_sp.reset (new StreamString());
m_err_stream.SetStreamAtIndex (eStreamStringIndex, stream_sp);
}
return m_error_stream;
return m_err_stream;
}
void
SetImmediateOutputFile (FILE *fh)
SetImmediateOutputFile (FILE *fh, bool transfer_fh_ownership = false)
{
lldb::StreamSP new_stream_sp (new StreamFile (fh, false));
m_output_stream.SetStream2 (new_stream_sp);
lldb::StreamSP stream_sp (new StreamFile (fh, transfer_fh_ownership));
m_out_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp);
}
void
SetImmediateErrorFile (FILE *fh)
SetImmediateErrorFile (FILE *fh, bool transfer_fh_ownership = false)
{
lldb::StreamSP new_stream_sp (new StreamFile (fh, false));
SetImmediateOutputStream (new_stream_sp);
lldb::StreamSP stream_sp (new StreamFile (fh, transfer_fh_ownership));
m_out_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp);
}
void
SetImmediateOutputStream (lldb::StreamSP &new_stream_sp)
SetImmediateOutputStream (const lldb::StreamSP &stream_sp)
{
m_output_stream.SetStream2 (new_stream_sp);
m_out_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp);
}
void
SetImmediateErrorStream (lldb::StreamSP &new_stream_sp)
SetImmediateErrorStream (const lldb::StreamSP &stream_sp)
{
m_error_stream.SetStream2 (new_stream_sp);
// Ensure we always have our normal output stream
m_err_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp);
}
lldb::StreamSP &
lldb::StreamSP
GetImmediateOutputStream ()
{
return m_output_stream.GetStream2 ();
return m_out_stream.GetStreamAtIndex (eImmediateStreamIndex);
}
lldb::StreamSP &
lldb::StreamSP
GetImmediateErrorStream ()
{
return m_error_stream.GetStream2 ();
return m_err_stream.GetStreamAtIndex (eImmediateStreamIndex);
}
void
@ -155,10 +159,14 @@ public:
void SetDidChangeProcessState (bool b);
private:
lldb::StreamSP m_output_stream_string_sp;
lldb::StreamSP m_error_stream_string_sp;
StreamTee m_output_stream;
StreamTee m_error_stream;
enum
{
eStreamStringIndex = 0,
eImmediateStreamIndex = 1
};
StreamTee m_out_stream;
StreamTee m_err_stream;
lldb::ReturnStatus m_status;
bool m_did_change_process_state;

View File

@ -292,3 +292,17 @@ SBCommandInterpreter::GetBroadcaster ()
return broadcaster;
}
const char *
SBCommandInterpreter::GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type)
{
return CommandObject::GetArgumentTypeAsCString (arg_type);
}
const char *
SBCommandInterpreter::GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type)
{
return CommandObject::GetArgumentDescriptionAsCString (arg_type);
}

View File

@ -92,27 +92,27 @@ CommandInterpreter::Initialize ()
LoadCommandDictionary ();
// Set up some initial aliases.
result.Clear(); HandleCommand ("command alias q quit", false, result);
result.Clear(); HandleCommand ("command alias run process launch --", false, result);
result.Clear(); HandleCommand ("command alias r process launch --", false, result);
result.Clear(); HandleCommand ("command alias c process continue", false, result);
result.Clear(); HandleCommand ("command alias continue process continue", false, result);
result.Clear(); HandleCommand ("command alias expr expression", false, result);
result.Clear(); HandleCommand ("command alias exit quit", false, result);
result.Clear(); HandleCommand ("command alias b regexp-break", false, result);
result.Clear(); HandleCommand ("command alias bt thread backtrace", false, result);
result.Clear(); HandleCommand ("command alias si thread step-inst", false, result);
result.Clear(); HandleCommand ("command alias step thread step-in", false, result);
result.Clear(); HandleCommand ("command alias s thread step-in", false, result);
result.Clear(); HandleCommand ("command alias next thread step-over", false, result);
result.Clear(); HandleCommand ("command alias n thread step-over", false, result);
result.Clear(); HandleCommand ("command alias finish thread step-out", false, result);
result.Clear(); HandleCommand ("command alias x memory read", false, result);
result.Clear(); HandleCommand ("command alias l source list", false, result);
result.Clear(); HandleCommand ("command alias list source list", false, result);
result.Clear(); HandleCommand ("command alias p frame variable", false, result);
result.Clear(); HandleCommand ("command alias print frame variable", false, result);
result.Clear(); HandleCommand ("command alias po expression -o --", false, result);
HandleCommand ("command alias q quit", false, result);
HandleCommand ("command alias run process launch --", false, result);
HandleCommand ("command alias r process launch --", false, result);
HandleCommand ("command alias c process continue", false, result);
HandleCommand ("command alias continue process continue", false, result);
HandleCommand ("command alias expr expression", false, result);
HandleCommand ("command alias exit quit", false, result);
HandleCommand ("command alias b regexp-break", false, result);
HandleCommand ("command alias bt thread backtrace", false, result);
HandleCommand ("command alias si thread step-inst", false, result);
HandleCommand ("command alias step thread step-in", false, result);
HandleCommand ("command alias s thread step-in", false, result);
HandleCommand ("command alias next thread step-over", false, result);
HandleCommand ("command alias n thread step-over", false, result);
HandleCommand ("command alias finish thread step-out", false, result);
HandleCommand ("command alias x memory read", false, result);
HandleCommand ("command alias l source list", false, result);
HandleCommand ("command alias list source list", false, result);
HandleCommand ("command alias p frame variable", false, result);
HandleCommand ("command alias print frame variable", false, result);
HandleCommand ("command alias po expression -o --", false, result);
}
const char *
@ -1517,9 +1517,6 @@ CommandInterpreter::HandleCommands (StringList &commands,
CommandReturnObject &result)
{
size_t num_lines = commands.GetSize();
CommandReturnObject tmp_result;
tmp_result.SetImmediateOutputStream (result.GetImmediateOutputStream ());
tmp_result.SetImmediateErrorStream (result.GetImmediateErrorStream ());
// If we are going to continue past a "continue" then we need to run the commands synchronously.
// Make sure you reset this value anywhere you return from the function.
@ -1543,7 +1540,6 @@ CommandInterpreter::HandleCommands (StringList &commands,
if (cmd[0] == '\0')
continue;
tmp_result.Clear();
if (echo_commands)
{
result.AppendMessageWithFormat ("%s %s\n",
@ -1551,6 +1547,9 @@ CommandInterpreter::HandleCommands (StringList &commands,
cmd);
}
CommandReturnObject tmp_result;
tmp_result.SetImmediateOutputStream (result.GetImmediateOutputStream ());
tmp_result.SetImmediateErrorStream (result.GetImmediateErrorStream ());
bool success = HandleCommand(cmd, false, tmp_result, NULL);
if (print_results)

View File

@ -600,6 +600,23 @@ BreakpointIDRangeHelpTextCallback ()
return "A 'breakpoint id list' is a manner of specifying multiple breakpoints. This can be done through several mechanisms. The easiest way is to just enter a space-separated list of breakpoint ids. To specify all the breakpoint locations under a major breakpoint, you can use the major breakpoint number followed by '.*', eg. '5.*' means all the locations under breakpoint 5. You can also indicate a range of breakpoints by using <start-bp-id> - <end-bp-id>. The start-bp-id and end-bp-id for a range can be any valid breakpoint ids. It is not legal, however, to specify a range using specific locations that cross major breakpoint numbers. I.e. 3.2 - 3.7 is legal; 2 - 5 is legal; but 3.2 - 4.4 is not legal.";
}
const char *
CommandObject::GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type)
{
if (arg_type >=0 && arg_type < eArgTypeLastArg)
return g_arguments_data[arg_type].arg_name;
return NULL;
}
const char *
CommandObject::GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type)
{
if (arg_type >=0 && arg_type < eArgTypeLastArg)
return g_arguments_data[arg_type].help_text;
return NULL;
}
CommandObject::ArgumentTableEntry
CommandObject::g_arguments_data[] =
{
@ -667,6 +684,8 @@ CommandObject::g_arguments_data[] =
const CommandObject::ArgumentTableEntry*
CommandObject::GetArgumentTable ()
{
// If this assertion fires, then the table above is out of date with the CommandArgumentType enumeration
assert ((sizeof (CommandObject::g_arguments_data) / sizeof (CommandObject::ArgumentTableEntry)) == eArgTypeLastArg);
return CommandObject::g_arguments_data;
}

View File

@ -19,10 +19,8 @@ using namespace lldb;
using namespace lldb_private;
CommandReturnObject::CommandReturnObject () :
m_error_stream_string_sp (),
m_output_stream_string_sp (),
m_output_stream (),
m_error_stream (),
m_out_stream (),
m_err_stream (),
m_status (eReturnStatusStarted),
m_did_change_process_state (false)
{
@ -145,11 +143,15 @@ CommandReturnObject::HasResult ()
void
CommandReturnObject::Clear()
{
if (m_output_stream_string_sp)
static_cast<StreamString *>(m_output_stream_string_sp.get())->Clear();
if (m_error_stream_string_sp)
static_cast<StreamString *>(m_error_stream_string_sp.get())->Clear();
lldb::StreamSP stream_sp;
stream_sp = m_out_stream.GetStreamAtIndex (eStreamStringIndex);
if (stream_sp)
static_cast<StreamString *>(stream_sp.get())->Clear();
stream_sp = m_err_stream.GetStreamAtIndex (eStreamStringIndex);
if (stream_sp)
static_cast<StreamString *>(stream_sp.get())->Clear();
m_status = eReturnStatusStarted;
m_did_change_process_state = false;
}
bool

View File

@ -181,35 +181,6 @@ OutputFormattedUsageText (FILE *out, int indent, const char *text, int output_ma
}
}
void
GetArgumentName (const CommandArgumentType arg_type, std::string &arg_name)
{
//Fudge this function here, since we can't call the "real" version in lldb_private::CommandObject...
switch (arg_type)
{
// Make cases for all the arg_types used in Driver.cpp
case eArgTypeNone:
arg_name = "";
break;
case eArgTypeArchitecture:
arg_name = "architecture";
break;
case eArgTypeScriptLang:
arg_name = "script-language";
break;
case eArgTypeFilename:
arg_name = "filename";
break;
}
return;
}
void
ShowUsage (FILE *out, lldb::OptionDefinition *option_table, Driver::OptionData data)
{
@ -265,23 +236,22 @@ ShowUsage (FILE *out, lldb::OptionDefinition *option_table, Driver::OptionData d
if (option_table[i].usage_mask & opt_set_mask)
{
CommandArgumentType arg_type = option_table[i].argument_type;
std::string arg_name;
GetArgumentName (arg_type, arg_name);
const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString (arg_type);
if (option_table[i].required)
{
if (option_table[i].option_has_arg == required_argument)
fprintf (out, " -%c <%s>", option_table[i].short_option, arg_name.c_str());
fprintf (out, " -%c <%s>", option_table[i].short_option, arg_name);
else if (option_table[i].option_has_arg == optional_argument)
fprintf (out, " -%c [<%s>]", option_table[i].short_option, arg_name.c_str());
fprintf (out, " -%c [<%s>]", option_table[i].short_option, arg_name);
else
fprintf (out, " -%c", option_table[i].short_option);
}
else
{
if (option_table[i].option_has_arg == required_argument)
fprintf (out, " [-%c <%s>]", option_table[i].short_option, arg_name.c_str());
fprintf (out, " [-%c <%s>]", option_table[i].short_option, arg_name);
else if (option_table[i].option_has_arg == optional_argument)
fprintf (out, " [-%c [<%s>]]", option_table[i].short_option, arg_name.c_str());
fprintf (out, " [-%c [<%s>]]", option_table[i].short_option, arg_name);
else
fprintf (out, " [-%c]", option_table[i].short_option);
}
@ -311,17 +281,16 @@ ShowUsage (FILE *out, lldb::OptionDefinition *option_table, Driver::OptionData d
if (pos == options_seen.end())
{
CommandArgumentType arg_type = option_table[i].argument_type;
std::string arg_name;
GetArgumentName (arg_type, arg_name);
const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString (arg_type);
options_seen.insert (option_table[i].short_option);
fprintf (out, "%*s-%c ", indent_level, "", option_table[i].short_option);
if (arg_type != eArgTypeNone)
fprintf (out, "<%s>", arg_name.c_str());
fprintf (out, "<%s>", arg_name);
fprintf (out, "\n");
fprintf (out, "%*s--%s ", indent_level, "", option_table[i].long_option);
if (arg_type != eArgTypeNone)
fprintf (out, "<%s>", arg_name.c_str());
fprintf (out, "<%s>", arg_name);
fprintf (out, "\n");
indent_level += 5;
OutputFormattedUsageText (out, indent_level, option_table[i].usage_text, screen_width);