aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Weinhold <ingo_weinhold@gmx.de>2012-07-20 23:30:34 +0200
committerIngo Weinhold <ingo_weinhold@gmx.de>2012-07-20 23:32:58 +0200
commit6d60b554e6d6cee2a7e73e95b5e06374c9f2e32f (patch)
tree86eeddd0a96cb4f18bd52ca90e8b8e925da090c5
parent0f1f968ffb6f4b19193ccad1a4edae9e9a46ab19 (diff)
Debugger: Some basic work to get the CLI goinghrev44364
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.
-rw-r--r--src/apps/debugger/Jamfile7
-rw-r--r--src/apps/debugger/user_interface/cli/CliCommand.cpp20
-rw-r--r--src/apps/debugger/user_interface/cli/CliCommand.h33
-rw-r--r--src/apps/debugger/user_interface/cli/CliContext.h13
-rw-r--r--src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp236
-rw-r--r--src/apps/debugger/user_interface/cli/CommandLineUserInterface.h35
6 files changed, 338 insertions, 6 deletions
diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile
index 193bc20961..80c98fe660 100644
--- a/src/apps/debugger/Jamfile
+++ b/src/apps/debugger/Jamfile
@@ -169,12 +169,13 @@ Application Debugger :
# user_interface
UserInterface.cpp
- # user_interface/gui
- GraphicalUserInterface.cpp
-
# user_interface/cli
+ CliCommand.cpp
CommandLineUserInterface.cpp
+ # user_interface/gui
+ GraphicalUserInterface.cpp
+
# user_interface/gui/model
VariablesViewState.cpp
VariablesViewStateHistory.cpp
diff --git a/src/apps/debugger/user_interface/cli/CliCommand.cpp b/src/apps/debugger/user_interface/cli/CliCommand.cpp
new file mode 100644
index 0000000000..c83c8cfbad
--- /dev/null
+++ b/src/apps/debugger/user_interface/cli/CliCommand.cpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * 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()
+{
+}
diff --git a/src/apps/debugger/user_interface/cli/CliCommand.h b/src/apps/debugger/user_interface/cli/CliCommand.h
new file mode 100644
index 0000000000..2a65e19aa3
--- /dev/null
+++ b/src/apps/debugger/user_interface/cli/CliCommand.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * 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
diff --git a/src/apps/debugger/user_interface/cli/CliContext.h b/src/apps/debugger/user_interface/cli/CliContext.h
new file mode 100644
index 0000000000..df318160a9
--- /dev/null
+++ b/src/apps/debugger/user_interface/cli/CliContext.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef CLI_CONTEXT_H
+#define CLI_CONTEXT_H
+
+
+class CliContext {
+};
+
+
+#endif // CLI_CONTEXT_H
diff --git a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp
index 95fd5f29fb..ab53011fb2 100644
--- a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp
+++ b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp
@@ -1,13 +1,106 @@
/*
* Copyright 2011, Rene Gollent, rene@gollent.com.
+ * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* 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());
+ }
+}
diff --git a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.h b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.h
index 4d04a7c2ee..b581f36b90 100644
--- a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.h
+++ b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.h
@@ -1,14 +1,21 @@
/*
* Copyright 2011, Rene Gollent, rene@gollent.com.
+ * Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* 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;
};