diff options
Diffstat (limited to 'lldb/source/Interpreter/CommandObject.cpp')
-rw-r--r-- | lldb/source/Interpreter/CommandObject.cpp | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp new file mode 100644 index 00000000000..080b5b057bf --- /dev/null +++ b/lldb/source/Interpreter/CommandObject.cpp @@ -0,0 +1,448 @@ +//===-- CommandObject.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Interpreter/CommandObject.h" + +#include <string> +#include <map> + +#include <getopt.h> +#include <stdlib.h> +#include <ctype.h> + +#include "lldb/Core/Address.h" +#include "lldb/Core/Options.h" + +// These are for the Sourcename completers. +// FIXME: Make a separate file for the completers. +#include "lldb/Core/FileSpec.h" +#include "lldb/Core/FileSpecList.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Interpreter/ScriptInterpreterPython.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObject +//------------------------------------------------------------------------- + +CommandObject::CommandObject (const char *name, const char *help, const char *syntax, uint32_t flags) : + m_cmd_name (name), + m_cmd_help_short (), + m_cmd_help_long (), + m_cmd_syntax (), + m_flags (flags) +{ + if (help && help[0]) + m_cmd_help_short = help; + if (syntax && syntax[0]) + m_cmd_syntax = syntax; +} + +CommandObject::~CommandObject () +{ +} + +const char * +CommandObject::GetHelp () +{ + return m_cmd_help_short.c_str(); +} + +const char * +CommandObject::GetHelpLong () +{ + return m_cmd_help_long.c_str(); +} + +const char * +CommandObject::GetSyntax () +{ + return m_cmd_syntax.c_str(); +} + +const char * +CommandObject::Translate () +{ + //return m_cmd_func_name.c_str(); + return "This function is currently not implemented."; +} + +const char * +CommandObject::GetCommandName () +{ + return m_cmd_name.c_str(); +} + +void +CommandObject::SetCommandName (const char *name) +{ + m_cmd_name = name; +} + +void +CommandObject::SetHelp (const char *cstr) +{ + m_cmd_help_short = cstr; +} + +void +CommandObject::SetHelpLong (const char *cstr) +{ + m_cmd_help_long = cstr; +} + +void +CommandObject::SetSyntax (const char *cstr) +{ + m_cmd_syntax = cstr; +} + +Options * +CommandObject::GetOptions () +{ + // By default commands don't have options unless this virtual function + // is overridden by base classes. + return NULL; +} + +Flags& +CommandObject::GetFlags() +{ + return m_flags; +} + +const Flags& +CommandObject::GetFlags() const +{ + return m_flags; +} + +bool +CommandObject::ExecuteCommandString +( + const char *command_line, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + Args command_args(command_line); + return ExecuteWithOptions (command_args, context, interpreter, result); +} + +bool +CommandObject::ParseOptions +( + Args& args, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + // See if the subclass has options? + Options *options = GetOptions(); + if (options != NULL) + { + Error error; + options->ResetOptionValues(); + + // ParseOptions calls getopt_long, which always skips the zero'th item in the array and starts at position 1, + // so we need to push a dummy value into position zero. + args.Unshift("dummy_string"); + error = args.ParseOptions (*options); + + // The "dummy_string" will have already been removed by ParseOptions, + // so no need to remove it. + + if (error.Fail() || !options->VerifyOptions (result)) + { + const char *error_cstr = error.AsCString(); + if (error_cstr) + { + // We got an error string, lets use that + result.GetErrorStream().PutCString(error_cstr); + } + else + { + // No error string, output the usage information into result + options->GenerateOptionUsage (result.GetErrorStream(), this); + } + // Set the return status to failed (this was an error). + result.SetStatus (eReturnStatusFailed); + return false; + } + } + return true; +} +bool +CommandObject::ExecuteWithOptions +( + Args& args, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + for (size_t i = 0; i < args.GetArgumentCount(); ++i) + { + const char *tmp_str = args.GetArgumentAtIndex (i); + if (tmp_str[0] == '`') // back-quote + args.ReplaceArgumentAtIndex (i, interpreter->ProcessEmbeddedScriptCommands (tmp_str)); + } + + Process *process = context->GetExecutionContext().process; + if (process == NULL) + { + if (GetFlags().IsSet(CommandObject::eFlagProcessMustBeLaunched | CommandObject::eFlagProcessMustBePaused)) + { + result.AppendError ("Process must exist."); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + StateType state = process->GetState(); + + switch (state) + { + + case eStateAttaching: + case eStateLaunching: + case eStateSuspended: + case eStateCrashed: + case eStateStopped: + break; + + case eStateDetached: + case eStateExited: + case eStateUnloaded: + if (GetFlags().IsSet(CommandObject::eFlagProcessMustBeLaunched)) + { + result.AppendError ("Process must be launched."); + result.SetStatus (eReturnStatusFailed); + return false; + } + break; + + case eStateRunning: + case eStateStepping: + if (GetFlags().IsSet(CommandObject::eFlagProcessMustBePaused)) + { + result.AppendError ("Process is running. Use 'process interrupt' to pause execution."); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + } + + if (!ParseOptions (args, interpreter, result)) + return false; + + // Call the command-specific version of 'Execute', passing it the already processed arguments. + return Execute (args, context, interpreter, result); +} + +class CommandDictCommandPartialMatch +{ + public: + CommandDictCommandPartialMatch (const char *match_str) + { + m_match_str = match_str; + } + bool operator() (const std::pair<std::string, lldb::CommandObjectSP> map_element) const + { + // A NULL or empty string matches everything. + if (m_match_str == NULL || *m_match_str == '\0') + return 1; + + size_t found = map_element.first.find (m_match_str, 0); + if (found == std::string::npos) + return 0; + else + return found == 0; + } + + private: + const char *m_match_str; +}; + +int +CommandObject::AddNamesMatchingPartialString (CommandObject::CommandMap &in_map, const char *cmd_str, + StringList &matches) +{ + int number_added = 0; + CommandDictCommandPartialMatch matcher(cmd_str); + + CommandObject::CommandMap::iterator matching_cmds = std::find_if (in_map.begin(), in_map.end(), matcher); + + while (matching_cmds != in_map.end()) + { + ++number_added; + matches.AppendString((*matching_cmds).first.c_str()); + matching_cmds = std::find_if (++matching_cmds, in_map.end(), matcher);; + } + return number_added; +} + +int +CommandObject::HandleCompletion +( + Args &input, + int &cursor_index, + int &cursor_char_position, + int match_start_point, + int max_return_elements, + CommandInterpreter *interpreter, + StringList &matches +) +{ + if (WantsRawCommandString()) + { + // FIXME: Abstract telling the completion to insert the completion character. + matches.Clear(); + return -1; + } + else + { + // Can we do anything generic with the options? + Options *cur_options = GetOptions(); + CommandReturnObject result; + OptionElementVector opt_element_vector; + + if (cur_options != NULL) + { + // Re-insert the dummy command name string which will have been + // stripped off: + input.Unshift ("dummy-string"); + cursor_index++; + + + // I stick an element on the end of the input, because if the last element is + // option that requires an argument, getopt_long will freak out. + + input.AppendArgument ("<FAKE-VALUE>"); + + input.ParseArgsForCompletion (*cur_options, opt_element_vector); + + input.DeleteArgumentAtIndex(input.GetArgumentCount() - 1); + + bool handled_by_options; + handled_by_options = cur_options->HandleOptionCompletion(input, + opt_element_vector, + cursor_index, + cursor_char_position, + match_start_point, + max_return_elements, + interpreter, + matches); + if (handled_by_options) + return matches.GetSize(); + } + + // If we got here, the last word is not an option or an option argument. + return HandleArgumentCompletion(input, + cursor_index, + cursor_char_position, + opt_element_vector, + match_start_point, + max_return_elements, + interpreter, + matches); + } +} + +int +CommandObject::HandleArgumentCompletion +( + Args &input, + int &cursor_index, + int &cursor_char_position, + OptionElementVector &opt_element_vector, + int match_start_point, + int max_return_elements, + CommandInterpreter *interpreter, + StringList &matches +) +{ + return 0; +} + +// Case insensitive version of ::strstr() +// Returns true if s2 is contained within s1. + +static bool +contains_string (const char *s1, const char *s2) +{ + char *locase_s1 = (char *) malloc (strlen (s1) + 1); + char *locase_s2 = (char *) malloc (strlen (s2) + 1); + int i; + for (i = 0; s1 && s1[i] != '\0'; i++) + locase_s1[i] = ::tolower (s1[i]); + locase_s1[i] = '\0'; + for (i = 0; s2 && s2[i] != '\0'; i++) + locase_s2[i] = ::tolower (s2[i]); + locase_s2[i] = '\0'; + + const char *result = ::strstr (locase_s1, locase_s2); + free (locase_s1); + free (locase_s2); + // 'result' points into freed memory - but we're not + // deref'ing it so hopefully current/future compilers + // won't complain.. + + if (result == NULL) + return false; + else + return true; +} + +bool +CommandObject::HelpTextContainsWord (const char *search_word) +{ + const char *short_help; + const char *long_help; + const char *syntax_help; + std::string options_usage_help; + + + bool found_word = false; + + short_help = GetHelp(); + long_help = GetHelpLong(); + syntax_help = GetSyntax(); + + if (contains_string (short_help, search_word)) + found_word = true; + else if (contains_string (long_help, search_word)) + found_word = true; + else if (contains_string (syntax_help, search_word)) + found_word = true; + + if (!found_word + && GetOptions() != NULL) + { + StreamString usage_help; + GetOptions()->GenerateOptionUsage (usage_help, this); + if (usage_help.GetSize() > 0) + { + const char *usage_text = usage_help.GetData(); + if (contains_string (usage_text, search_word)) + found_word = true; + } + } + + return found_word; +} |