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/cli + CliCommand.cpp + CommandLineUserInterface.cpp + # user_interface/gui GraphicalUserInterface.cpp - # user_interface/cli - CommandLineUserInterface.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 + + +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 + +#include + +#include +#include + +#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 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 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 +#include + #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 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; };