<rdar://problem/10605072>

Added the ability to override command line commands. In some cases GUI interfaces
might want to intercept commands like "quit" or "process launch" (which might cause
the process to re-run). They can now do so by overriding/intercepting commands
by using functions added to SBCommandInterpreter using a callback function. If the
callback function returns true, the command is assumed to be handled. If false
is returned the command should be evaluated normally.

Adopted this up in the Driver.cpp for intercepting the "quit" command.

llvm-svn: 151708
This commit is contained in:
Greg Clayton 2012-02-29 04:21:24 +00:00
parent e4f22dfa95
commit a9f7b79dfe
9 changed files with 110 additions and 52 deletions

View File

@ -92,6 +92,13 @@ public:
int max_return_elements,
lldb::SBStringList &matches);
// Catch commands before they execute by registering a callback that will
// get called when the command gets executed. This allows GUI or command
// line interfaces to intercept a command and stop it from happening
bool
SetCommandOverrideCallback (const char *command_name,
lldb::CommandOverrideCallback callback,
void *baton);
protected:
lldb_private::CommandInterpreter &

View File

@ -194,11 +194,6 @@ public:
eFlagProcessMustBePaused = (1 << 1)
};
// Do not override this
bool
ExecuteCommandString (const char *command,
CommandReturnObject &result);
bool
ParseOptions (Args& args,
CommandReturnObject &result);
@ -369,6 +364,25 @@ public:
return NULL;
}
CommandOverrideCallback
GetOverrideCallback () const
{
return m_command_override_callback;
}
void *
GetOverrideCallbackBaton () const
{
return m_command_override_baton;
}
void
SetOverrideCallback (CommandOverrideCallback callback, void *baton)
{
m_command_override_callback = callback;
m_command_override_baton = baton;
}
protected:
CommandInterpreter &m_interpreter;
std::string m_cmd_name;
@ -378,7 +392,8 @@ protected:
bool m_is_alias;
Flags m_flags;
std::vector<CommandArgumentEntry> m_arguments;
CommandOverrideCallback m_command_override_callback;
void * m_command_override_baton;
// Helper function to populate IDs or ID ranges as the command argument data
// to the specified command argument entry.
static void

View File

@ -35,6 +35,7 @@ namespace lldb_private
typedef ThreadPlan * (*ThreadPlanShouldStopHereCallback) (ThreadPlan *current_plan, Flags &flags, void *baton);
typedef UnwindAssembly* (*UnwindAssemblyCreateInstance) (const ArchSpec &arch);
typedef int (*ComparisonFunction)(const void *, const void *);
typedef bool (*CommandOverrideCallback)(void *baton, const char **argv);
} // namespace lldb_private

View File

@ -49,32 +49,8 @@ namespace lldb {
typedef void * thread_arg_t; // Host thread argument type
typedef void * thread_result_t; // Host thread result type
typedef void * (*thread_func_t)(void *); // Host thread function type
// The template below can be used in a few useful ways:
//
// // Make a single shared pointer a class Foo
// lldb::SharePtr<Foo>::Type foo_sp;
//
// // Make a typedef to a Foo shared pointer
// typedef lldb::SharePtr<Foo>::Type FooSP;
//
// template<typename _Tp>
// struct SharedPtr
// {
// typedef lldb_private::SharingPtr<_Tp> Type;
// };
// template<typename _Tp>
// struct LoggingSharedPtr
// {
// typedef lldb_private::LoggingSharingPtr<_Tp> Type;
// };
//
// template <typename _Tp>
// struct IntrusiveSharedPtr
// {
// typedef lldb_private::IntrusiveSharingPtr<_Tp> Type;
// };
typedef void (*LogOutputCallback) (const char *, void *baton);
typedef bool (*CommandOverrideCallback)(void *baton, const char **argv);
} // namespace lldb
#if defined(__MINGW32__)

View File

@ -310,6 +310,22 @@ SBCommandInterpreter::GetArgumentDescriptionAsCString (const lldb::CommandArgume
return CommandObject::GetArgumentDescriptionAsCString (arg_type);
}
bool
SBCommandInterpreter::SetCommandOverrideCallback (const char *command_name,
lldb::CommandOverrideCallback callback,
void *baton)
{
if (command_name && command_name[0] && m_opaque_ptr)
{
CommandObject *cmd_obj = m_opaque_ptr->GetCommandObject(command_name);
if (cmd_obj)
{
cmd_obj->SetOverrideCallback (callback, baton);
return true;
}
}
return false;
}
#ifndef LLDB_DISABLE_PYTHON
@ -341,3 +357,4 @@ SBCommandInterpreter::InitializeSWIG ()
#endif
}
}

View File

@ -1511,11 +1511,32 @@ CommandInterpreter::HandleCommand (const char *command_line,
log->Printf ("HandleCommand, command line after removing command name(s): '%s'", remainder.c_str());
CommandOverrideCallback command_callback = cmd_obj->GetOverrideCallback();
bool handled = false;
if (wants_raw_input)
{
if (command_callback)
{
std::string full_command (cmd_obj->GetCommandName ());
full_command += ' ';
full_command += remainder;
const char *argv[2] = { NULL, NULL };
argv[0] = full_command.c_str();
handled = command_callback (cmd_obj->GetOverrideCallbackBaton(), argv);
}
if (!handled)
cmd_obj->ExecuteRawCommandString (remainder.c_str(), result);
}
else
{
Args cmd_args (remainder.c_str());
if (command_callback)
{
Args full_args (cmd_obj->GetCommandName ());
full_args.AppendArguments(cmd_args);
handled = command_callback (cmd_obj->GetOverrideCallbackBaton(), full_args.GetConstArgumentVector());
}
if (!handled)
cmd_obj->ExecuteWithOptions (cmd_args, result);
}
}

View File

@ -53,7 +53,9 @@ CommandObject::CommandObject
m_cmd_syntax (),
m_is_alias (false),
m_flags (flags),
m_arguments()
m_arguments(),
m_command_override_callback (NULL),
m_command_override_baton (NULL)
{
if (help && help[0])
m_cmd_help_short = help;
@ -162,17 +164,6 @@ CommandObject::GetFlags() const
return m_flags;
}
bool
CommandObject::ExecuteCommandString
(
const char *command_line,
CommandReturnObject &result
)
{
Args command_args(command_line);
return ExecuteWithOptions (command_args, result);
}
bool
CommandObject::ParseOptions
(

View File

@ -1088,6 +1088,14 @@ Driver::EditLineInputReaderCallback
return bytes_len;
}
// Intercept when the quit command is called and tell our driver that it is done
static bool
QuitCommandOverrideCallback (void *baton, const char **argv)
{
((Driver *)baton)->SetIsDone();
return true;
}
void
Driver::MainLoop ()
{
@ -1190,6 +1198,10 @@ Driver::MainLoop ()
SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
// Intercept when the quit command is called and tell our driver that it is done
bool quit_success = sb_interpreter.SetCommandOverrideCallback ("quit", QuitCommandOverrideCallback, this);
assert (quit_success);
m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, editline_output_slave_fh, stdout, stderr, this));
SBCommunication out_comm_2("driver.editline_output");
@ -1371,8 +1383,7 @@ Driver::MainLoop ()
ReadyForCommand ();
bool done = false;
while (!done)
while (!GetIsDone())
{
listener.WaitForEvent (UINT32_MAX, event);
if (event.IsValid())
@ -1385,12 +1396,15 @@ Driver::MainLoop ()
if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
(event_type & IOChannel::eBroadcastBitThreadDidExit))
{
done = true;
SetIsDone();
if (event_type & IOChannel::eBroadcastBitThreadDidExit)
iochannel_thread_exited = true;
}
else
done = HandleIOEvent (event);
{
if (HandleIOEvent (event))
SetIsDone();
}
}
else if (SBProcess::EventIsProcessEvent (event))
{
@ -1402,9 +1416,12 @@ Driver::MainLoop ()
}
else if (event.BroadcasterMatchesRef (sb_interpreter.GetBroadcaster()))
{
// TODO: deprecate the eBroadcastBitQuitCommandReceived event
// now that we have SBCommandInterpreter::SetCommandOverrideCallback()
// that can take over a command
if (event_type & SBCommandInterpreter::eBroadcastBitQuitCommandReceived)
{
done = true;
SetIsDone();
}
else if (event_type & SBCommandInterpreter::eBroadcastBitAsynchronousErrorData)
{

View File

@ -135,6 +135,18 @@ public:
return m_debugger.InputReaderIsTopReader (m_editline_reader);
}
bool
GetIsDone () const
{
return m_done;
}
void
SetIsDone ()
{
m_done = true;
}
private:
lldb::SBDebugger m_debugger;
lldb_utility::PseudoTerminal m_editline_pty;
@ -143,6 +155,7 @@ private:
std::auto_ptr<IOChannel> m_io_channel_ap;
OptionData m_option_data;
bool m_waiting_for_command;
bool m_done;
void
ResetOptionValues ();