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:
Ingo Weinhold
2012-07-20 23:32:58 +02:00
parent 0f1f968ffb
commit 6d60b554e6
6 changed files with 338 additions and 6 deletions
+4 -3
View File
@@ -169,12 +169,13 @@ Application Debugger :
# user_interface
UserInterface.cpp
# user_interface/cli
CliCommand.cpp
CommandLineUserInterface.cpp
# user_interface/gui
GraphicalUserInterface.cpp
# user_interface/cli
CommandLineUserInterface.cpp
# user_interface/gui/model
VariablesViewState.cpp
VariablesViewStateHistory.cpp
@@ -0,0 +1,20 @@
/*
* Copyright 2012, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "CliCommand.h"
CliCommand::CliCommand(const char* summary, const char* usage)
:
fSummary(summary),
fUsage(usage)
{
}
CliCommand::~CliCommand()
{
}
@@ -0,0 +1,33 @@
/*
* Copyright 2012, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef CLI_COMMAND_H
#define CLI_COMMAND_H
#include <Referenceable.h>
class CliContext;
class CliCommand : public BReferenceable {
public:
CliCommand(const char* summary,
const char* usage);
virtual ~CliCommand();
const char* Summary() const { return fSummary; }
const char* Usage() const { return fUsage; }
virtual void Execute(int argc, const char* const* argv,
CliContext& context) = 0;
private:
const char* fSummary;
const char* fUsage;
};
#endif // CLI_COMMAND_H
@@ -0,0 +1,13 @@
/*
* Copyright 2012, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef CLI_CONTEXT_H
#define CLI_CONTEXT_H
class CliContext {
};
#endif // CLI_CONTEXT_H
@@ -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());
}
}
@@ -1,14 +1,21 @@
/*
* Copyright 2011, Rene Gollent, [email protected].
* Copyright 2012, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef COMMAND_LINE_USER_INTERFACE_H
#define COMMAND_LINE_USER_INTERFACE_H
#include <ObjectList.h>
#include <String.h>
#include "UserInterface.h"
class CliCommand;
class CommandLineUserInterface : public UserInterface {
public:
CommandLineUserInterface();
@@ -33,6 +40,34 @@ public:
const char* message, const char* choice1,
const char* choice2, const char* choice3);
private:
struct CommandEntry;
typedef BObjectList<CommandEntry> CommandList;
struct HelpCommand;
struct QuitCommand;
// GCC 2 support
friend struct HelpCommand;
friend struct QuitCommand;
private:
static status_t _InputLoopEntry(void* data);
status_t _InputLoop();
status_t _RegisterCommands();
bool _RegisterCommand(const BString& name,
CliCommand* command);
void _ExecuteCommand(int argc,
const char* const* argv);
void _PrintHelp();
private:
thread_id fThread;
Team* fTeam;
UserInterfaceListener* fListener;
CommandList fCommands;
bool fTerminating;
};