Debugger: Some basic work to get the CLI going
There's an input loop thread which reads and parses command lines and the infrastructure for registering and executing commands. Currently only "help" and "quit" commands are implemented.
This commit is contained in:
@@ -1,13 +1,106 @@
|
||||
/*
|
||||
* Copyright 2011, Rene Gollent, [email protected].
|
||||
* Copyright 2012, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "CommandLineUserInterface.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <ArgumentVector.h>
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "CliCommand.h"
|
||||
#include "CliContext.h"
|
||||
|
||||
|
||||
// #pragma mark - CommandEntry
|
||||
|
||||
|
||||
struct CommandLineUserInterface::CommandEntry {
|
||||
CommandEntry(const BString& name, CliCommand* command)
|
||||
:
|
||||
fName(name),
|
||||
fCommand(command)
|
||||
{
|
||||
}
|
||||
|
||||
const BString& Name() const
|
||||
{
|
||||
return fName;
|
||||
}
|
||||
|
||||
CliCommand* Command() const
|
||||
{
|
||||
return fCommand.Get();
|
||||
}
|
||||
|
||||
private:
|
||||
BString fName;
|
||||
BReference<CliCommand> fCommand;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - HelpCommand
|
||||
|
||||
|
||||
struct CommandLineUserInterface::HelpCommand : CliCommand {
|
||||
HelpCommand(CommandLineUserInterface* userInterface)
|
||||
:
|
||||
CliCommand("print a list of all commands",
|
||||
"%s\n"
|
||||
"Prints a list of all commands."),
|
||||
fUserInterface(userInterface)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Execute(int argc, const char* const* argv, CliContext& context)
|
||||
{
|
||||
fUserInterface->_PrintHelp();
|
||||
}
|
||||
|
||||
private:
|
||||
CommandLineUserInterface* fUserInterface;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - HelpCommand
|
||||
|
||||
|
||||
struct CommandLineUserInterface::QuitCommand : CliCommand {
|
||||
QuitCommand(CommandLineUserInterface* userInterface)
|
||||
:
|
||||
CliCommand("quit Debugger",
|
||||
"%s\n"
|
||||
"Quits Debugger."),
|
||||
fUserInterface(userInterface)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Execute(int argc, const char* const* argv, CliContext& context)
|
||||
{
|
||||
fUserInterface->fListener->UserInterfaceQuitRequested();
|
||||
}
|
||||
|
||||
private:
|
||||
CommandLineUserInterface* fUserInterface;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - CommandLineUserInterface
|
||||
|
||||
|
||||
CommandLineUserInterface::CommandLineUserInterface()
|
||||
:
|
||||
fThread(-1),
|
||||
fTeam(NULL),
|
||||
fListener(NULL),
|
||||
fCommands(20, true),
|
||||
fTerminating(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -27,33 +120,48 @@ CommandLineUserInterface::ID() const
|
||||
status_t
|
||||
CommandLineUserInterface::Init(Team* team, UserInterfaceListener* listener)
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
fTeam = team;
|
||||
fListener = listener;
|
||||
|
||||
status_t error = _RegisterCommands();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
fThread = spawn_thread(&_InputLoopEntry, "CLI", B_NORMAL_PRIORITY, this);
|
||||
if (fThread < 0)
|
||||
return fThread;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CommandLineUserInterface::Show()
|
||||
{
|
||||
resume_thread(fThread);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CommandLineUserInterface::Terminate()
|
||||
{
|
||||
fTerminating = true;
|
||||
// TODO: Signal the thread so it wakes up!
|
||||
wait_for_thread(fThread, NULL);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CommandLineUserInterface::LoadSettings(const TeamUISettings* settings)
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CommandLineUserInterface::SaveSettings(TeamUISettings*& settings) const
|
||||
{
|
||||
return B_UNSUPPORTED;;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,3 +179,125 @@ CommandLineUserInterface::SynchronouslyAskUser(const char* title,
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ status_t
|
||||
CommandLineUserInterface::_InputLoopEntry(void* data)
|
||||
{
|
||||
return ((CommandLineUserInterface*)data)->_InputLoop();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CommandLineUserInterface::_InputLoop()
|
||||
{
|
||||
while (!fTerminating) {
|
||||
// read a command line
|
||||
printf("debugger> ");
|
||||
fflush(stdout);
|
||||
char buffer[256];
|
||||
if (fgets(buffer, sizeof(buffer), stdin) == NULL)
|
||||
break;
|
||||
|
||||
// parse the command line
|
||||
ArgumentVector args;
|
||||
const char* parseErrorLocation;
|
||||
switch (args.Parse(buffer, &parseErrorLocation)) {
|
||||
case ArgumentVector::NO_ERROR:
|
||||
break;
|
||||
case ArgumentVector::NO_MEMORY:
|
||||
printf("Insufficient memory parsing the command line.\n");
|
||||
continue;
|
||||
case ArgumentVector::UNTERMINATED_QUOTED_STRING:
|
||||
printf("Parse error: Unterminated quoted string starting at "
|
||||
"character %zu.\n", parseErrorLocation - buffer + 1);
|
||||
continue;
|
||||
case ArgumentVector::TRAILING_BACKSPACE:
|
||||
printf("Parse error: trailing backspace.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (args.ArgumentCount() == 0)
|
||||
continue;
|
||||
|
||||
_ExecuteCommand(args.ArgumentCount(), args.Arguments());
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CommandLineUserInterface::_RegisterCommands()
|
||||
{
|
||||
if (_RegisterCommand("help", new(std::nothrow) HelpCommand(this)) &&
|
||||
_RegisterCommand("quit", new(std::nothrow) QuitCommand(this))) {
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CommandLineUserInterface::_RegisterCommand(const BString& name,
|
||||
CliCommand* command)
|
||||
{
|
||||
BReference<CliCommand> commandReference(command, true);
|
||||
if (name.IsEmpty() || command == NULL)
|
||||
return false;
|
||||
|
||||
CommandEntry* entry = new(std::nothrow) CommandEntry(name, command);
|
||||
if (entry == NULL || !fCommands.AddItem(entry)) {
|
||||
delete entry;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CommandLineUserInterface::_ExecuteCommand(int argc, const char* const* argv)
|
||||
{
|
||||
const char* commandName = argv[0];
|
||||
size_t commandNameLength = strlen(commandName);
|
||||
|
||||
CommandEntry* firstEntry = NULL;
|
||||
for (int32 i = 0; CommandEntry* entry = fCommands.ItemAt(i); i++) {
|
||||
if (entry->Name().Compare(commandName, commandNameLength) == 0) {
|
||||
if (firstEntry != NULL) {
|
||||
printf("Ambiguous command \"%s\".\n", commandName);
|
||||
return;
|
||||
}
|
||||
|
||||
firstEntry = entry;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstEntry == NULL) {
|
||||
printf("Unknown command \"%s\".\n", commandName);
|
||||
return;
|
||||
}
|
||||
|
||||
CliContext context;
|
||||
firstEntry->Command()->Execute(argc, argv, context);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CommandLineUserInterface::_PrintHelp()
|
||||
{
|
||||
// determine longest command name
|
||||
int32 longestCommandName = 0;
|
||||
for (int32 i = 0; CommandEntry* entry = fCommands.ItemAt(i); i++) {
|
||||
longestCommandName
|
||||
= std::max(longestCommandName, entry->Name().Length());
|
||||
}
|
||||
|
||||
// print the command list
|
||||
for (int32 i = 0; CommandEntry* entry = fCommands.ItemAt(i); i++) {
|
||||
printf("%*s - %s\n", (int)longestCommandName, entry->Name().String(),
|
||||
entry->Command()->Summary());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user