Add a "Confirm" function to the CommandInterpreter so you can confirm potentially dangerous operations in a generic way.

llvm-svn: 115546
This commit is contained in:
Jim Ingham 2010-10-04 19:49:29 +00:00
parent 308363336b
commit 97a6dc7e16
4 changed files with 121 additions and 2 deletions

View File

@ -15,6 +15,7 @@
#include "lldb/lldb-include.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Host/Predicate.h"
namespace lldb_private {
@ -88,6 +89,11 @@ public:
void
RefreshPrompt();
// If you want to read from an input reader synchronously, then just initialize the
// reader and then call WaitOnReaderIsDone, which will return when the reader is popped.
void
WaitOnReaderIsDone ();
protected:
friend class Debugger;
@ -104,6 +110,7 @@ protected:
bool m_done;
bool m_echo;
bool m_active;
Predicate<bool> m_reader_done;
private:
DISALLOW_COPY_AND_ASSIGN (InputReader);

View File

@ -157,7 +157,16 @@ public:
void
SetPrompt (const char *);
bool Confirm (const char *message, bool default_answer);
static size_t
GetConfirmationInputReaderCallback (void *baton,
InputReader &reader,
lldb::InputReaderAction action,
const char *bytes,
size_t bytes_len);
void
LoadCommandDictionary ();

View File

@ -23,7 +23,8 @@ InputReader::InputReader (Debugger &debugger) :
m_granularity (eInputReaderGranularityInvalid),
m_done (true),
m_echo (true),
m_active (false)
m_active (false),
m_reader_done (false)
{
}
@ -315,6 +316,7 @@ InputReader::Notify (InputReaderAction notification)
case eInputReaderActivate:
case eInputReaderReactivate:
m_active = true;
m_reader_done.SetValue(false, eBroadcastAlways);
break;
case eInputReaderDeactivate:
@ -327,4 +329,12 @@ InputReader::Notify (InputReaderAction notification)
}
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);
}

View File

@ -38,6 +38,7 @@
#include "lldb/Interpreter/Args.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/InputReader.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/Timer.h"
#include "lldb/Target/Process.h"
@ -778,6 +779,98 @@ CommandInterpreter::SetPrompt (const char *new_prompt)
m_debugger.SetPrompt (new_prompt);
}
size_t
CommandInterpreter::GetConfirmationInputReaderCallback (void *baton,
InputReader &reader,
lldb::InputReaderAction action,
const char *bytes,
size_t bytes_len)
{
FILE *out_fh = reader.GetDebugger().GetOutputFileHandle();
bool *response_ptr = (bool *) baton;
switch (action)
{
case eInputReaderActivate:
if (out_fh)
{
if (reader.GetPrompt())
::fprintf (out_fh, "%s", reader.GetPrompt());
}
break;
case eInputReaderDeactivate:
break;
case eInputReaderReactivate:
if (out_fh && reader.GetPrompt())
::fprintf (out_fh, "%s", reader.GetPrompt());
break;
case eInputReaderGotToken:
if (bytes_len == 0)
{
reader.SetIsDone(true);
}
else if (bytes[0] == 'y')
{
*response_ptr = true;
reader.SetIsDone(true);
}
else if (bytes[0] == 'n')
{
*response_ptr = false;
reader.SetIsDone(true);
}
else
{
if (out_fh && !reader.IsDone() && reader.GetPrompt())
{
::fprintf (out_fh, "Please answer \"y\" or \"n\"\n");
::fprintf (out_fh, "%s", reader.GetPrompt());
}
}
break;
case eInputReaderDone:
break;
}
return bytes_len;
}
bool
CommandInterpreter::Confirm (const char *message, bool default_answer)
{
// The default interpretation just pushes a new input reader and lets it get the answer:
InputReaderSP reader_sp (new InputReader(GetDebugger()));
bool response = default_answer;
if (reader_sp)
{
std::string prompt(message);
prompt.append(": [");
if (default_answer)
prompt.append ("Y/n] ");
else
prompt.append ("y/N] ");
Error err (reader_sp->Initialize (CommandInterpreter::GetConfirmationInputReaderCallback,
&response, // baton
eInputReaderGranularityLine, // token size, to pass to callback function
NULL, // end token
prompt.c_str(), // prompt
true)); // echo input
if (err.Success())
{
GetDebugger().PushInputReader (reader_sp);
}
reader_sp->WaitOnReaderIsDone();
}
return response;
}
void
CommandInterpreter::CrossRegisterCommand (const char * dest_cmd, const char * object_type)
{