summaryrefslogtreecommitdiffstats
path: root/lldb/source/Interpreter/CommandObject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Interpreter/CommandObject.cpp')
-rw-r--r--lldb/source/Interpreter/CommandObject.cpp448
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;
+}
OpenPOWER on IntegriCloud