diff options
Diffstat (limited to 'source/Interpreter')
-rw-r--r-- | source/Interpreter/Args.cpp | 100 | ||||
-rw-r--r-- | source/Interpreter/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/Interpreter/CommandAlias.cpp | 307 | ||||
-rw-r--r-- | source/Interpreter/CommandHistory.cpp | 21 | ||||
-rw-r--r-- | source/Interpreter/CommandInterpreter.cpp | 660 | ||||
-rw-r--r-- | source/Interpreter/CommandObject.cpp | 265 | ||||
-rw-r--r-- | source/Interpreter/CommandObjectScript.cpp | 9 | ||||
-rw-r--r-- | source/Interpreter/Makefile | 51 | ||||
-rw-r--r-- | source/Interpreter/OptionGroupValueObjectDisplay.cpp | 12 | ||||
-rw-r--r-- | source/Interpreter/OptionValueArray.cpp | 1 | ||||
-rw-r--r-- | source/Interpreter/OptionValueFileSpecLIst.cpp | 1 | ||||
-rw-r--r-- | source/Interpreter/OptionValuePathMappings.cpp | 81 | ||||
-rw-r--r-- | source/Interpreter/OptionValueProperties.cpp | 19 | ||||
-rw-r--r-- | source/Interpreter/Options.cpp | 315 |
14 files changed, 1072 insertions, 771 deletions
diff --git a/source/Interpreter/Args.cpp b/source/Interpreter/Args.cpp index 81e6b0aa1dbc..d90ef1d256a4 100644 --- a/source/Interpreter/Args.cpp +++ b/source/Interpreter/Args.cpp @@ -83,19 +83,22 @@ Args::~Args () } void -Args::Dump (Stream *s) +Args::Dump (Stream &s, const char *label_name) const { + if (!label_name) + return; + const size_t argc = m_argv.size(); for (size_t i=0; i<argc; ++i) { - s->Indent(); + s.Indent(); const char *arg_cstr = m_argv[i]; if (arg_cstr) - s->Printf("argv[%zi]=\"%s\"\n", i, arg_cstr); + s.Printf("%s[%zi]=\"%s\"\n", label_name, i, arg_cstr); else - s->Printf("argv[%zi]=NULL\n", i); + s.Printf("%s[%zi]=NULL\n", label_name, i); } - s->EOL(); + s.EOL(); } bool @@ -575,8 +578,8 @@ Args::ParseOptions (Options &options) } } } - Mutex::Locker options_locker(NULL); - OptionParser::Prepare(options_locker); + std::unique_lock<std::mutex> lock; + OptionParser::Prepare(lock); int val; while (1) { @@ -887,14 +890,43 @@ Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t } const char * -Args::GetShellSafeArgument (const char *unsafe_arg, std::string &safe_arg) +Args::GetShellSafeArgument (const FileSpec& shell, + const char *unsafe_arg, + std::string &safe_arg) { + struct ShellDescriptor + { + ConstString m_basename; + const char* m_escapables; + }; + + static ShellDescriptor g_Shells[] = { + {ConstString("bash")," '\"<>()&"}, + {ConstString("tcsh")," '\"<>()&$"}, + {ConstString("sh")," '\"<>()&"} + }; + + // safe minimal set + const char* escapables = " '\""; + + if (auto basename = shell.GetFilename()) + { + for (const auto& Shell : g_Shells) + { + if (Shell.m_basename == basename) + { + escapables = Shell.m_escapables; + break; + } + } + } + safe_arg.assign (unsafe_arg); size_t prev_pos = 0; while (prev_pos < safe_arg.size()) { // Escape spaces and quotes - size_t pos = safe_arg.find_first_of(" '\"", prev_pos); + size_t pos = safe_arg.find_first_of(escapables, prev_pos); if (pos != std::string::npos) { safe_arg.insert (pos, 1, '\\'); @@ -906,7 +938,6 @@ Args::GetShellSafeArgument (const char *unsafe_arg, std::string &safe_arg) return safe_arg.c_str(); } - int64_t Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, Error &error) { @@ -1108,6 +1139,47 @@ Args::LongestCommonPrefix (std::string &common_prefix) } } +bool +Args::ContainsEnvironmentVariable(const char *env_var_name) const +{ + // Validate args. + if (!env_var_name) + return false; + + // Check each arg to see if it matches the env var name. + for (size_t i = 0; i < GetArgumentCount(); ++i) + { + // Get the arg value. + const char *argument_value = GetArgumentAtIndex(i); + if (!argument_value) + continue; + + // Check if we are the "{env_var_name}={env_var_value}" style. + const char *equal_p = strchr(argument_value, '='); + if (equal_p) + { + if (strncmp(env_var_name, argument_value, + equal_p - argument_value) == 0) + { + // We matched. + return true; + } + } + else + { + // We're a simple {env_var_name}-style entry. + if (strcmp(argument_value, env_var_name) == 0) + { + // We matched. + return true; + } + } + } + + // We didn't find a match. + return false; +} + size_t Args::FindArgumentIndexForOption (Option *long_options, int long_options_index) { @@ -1190,8 +1262,8 @@ Args::ParseAliasOptions (Options &options, } } - Mutex::Locker options_locker(NULL); - OptionParser::Prepare(options_locker); + std::unique_lock<std::mutex> lock; + OptionParser::Prepare(lock); int val; while (1) { @@ -1368,8 +1440,8 @@ Args::ParseArgsForCompletion } } - Mutex::Locker options_locker(NULL); - OptionParser::Prepare(options_locker); + std::unique_lock<std::mutex> lock; + OptionParser::Prepare(lock); OptionParser::EnableError(false); int val; diff --git a/source/Interpreter/CMakeLists.txt b/source/Interpreter/CMakeLists.txt index b92128cd3011..76d046f7d802 100644 --- a/source/Interpreter/CMakeLists.txt +++ b/source/Interpreter/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_library(lldbInterpreter Args.cpp + CommandAlias.cpp CommandHistory.cpp CommandInterpreter.cpp CommandObject.cpp diff --git a/source/Interpreter/CommandAlias.cpp b/source/Interpreter/CommandAlias.cpp new file mode 100644 index 000000000000..a915d63e6541 --- /dev/null +++ b/source/Interpreter/CommandAlias.cpp @@ -0,0 +1,307 @@ +//===-- CommandAlias.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/CommandAlias.h" + +#include "llvm/Support/ErrorHandling.h" + +#include "lldb/Core/StreamString.h" +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/Options.h" + +using namespace lldb; +using namespace lldb_private; + +static bool +ProcessAliasOptionsArgs (lldb::CommandObjectSP &cmd_obj_sp, + const char *options_args, + OptionArgVectorSP &option_arg_vector_sp) +{ + bool success = true; + OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); + + if (!options_args || (strlen (options_args) < 1)) + return true; + + std::string options_string (options_args); + Args args (options_args); + CommandReturnObject result; + // Check to see if the command being aliased can take any command options. + Options *options = cmd_obj_sp->GetOptions (); + if (options) + { + // See if any options were specified as part of the alias; if so, handle them appropriately. + options->NotifyOptionParsingStarting (); + args.Unshift ("dummy_arg"); + args.ParseAliasOptions (*options, result, option_arg_vector, options_string); + args.Shift (); + if (result.Succeeded()) + options->VerifyPartialOptions (result); + if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted) + { + result.AppendError ("Unable to create requested alias.\n"); + return false; + } + } + + if (!options_string.empty()) + { + if (cmd_obj_sp->WantsRawCommandString ()) + option_arg_vector->push_back (OptionArgPair ("<argument>", + OptionArgValue (-1, + options_string))); + else + { + const size_t argc = args.GetArgumentCount(); + for (size_t i = 0; i < argc; ++i) + if (strcmp (args.GetArgumentAtIndex (i), "") != 0) + option_arg_vector->push_back + (OptionArgPair ("<argument>", + OptionArgValue (-1, + std::string (args.GetArgumentAtIndex (i))))); + } + } + + return success; +} + +CommandAlias::CommandAlias (CommandInterpreter &interpreter, + lldb::CommandObjectSP cmd_sp, + const char *options_args, + const char *name, + const char *help, + const char *syntax, + uint32_t flags) : + CommandObject(interpreter, + name, + help, + syntax, + flags), +m_underlying_command_sp(), +m_option_string(options_args ? options_args : ""), +m_option_args_sp(new OptionArgVector), +m_is_dashdash_alias(eLazyBoolCalculate), +m_did_set_help(false), +m_did_set_help_long(false) +{ + if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) + { + m_underlying_command_sp = cmd_sp; + for (int i = 0; + auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i); + i++) + { + m_arguments.push_back(*cmd_entry); + } + if (!help || !help[0]) + { + StreamString sstr; + StreamString translation_and_help; + GetAliasExpansion(sstr); + + translation_and_help.Printf ("(%s) %s", sstr.GetData(), GetUnderlyingCommand()->GetHelp()); + SetHelp(translation_and_help.GetData()); + } + } +} + +bool +CommandAlias::WantsRawCommandString() +{ + if (IsValid()) + return m_underlying_command_sp->WantsRawCommandString(); + return false; +} + +bool +CommandAlias::WantsCompletion() +{ + if (IsValid()) + return m_underlying_command_sp->WantsCompletion(); + return false; +} + +int +CommandAlias::HandleCompletion (Args &input, + int &cursor_index, + int &cursor_char_position, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + if (IsValid()) + return m_underlying_command_sp->HandleCompletion(input, + cursor_index, + cursor_char_position, + match_start_point, + max_return_elements, + word_complete, + matches); + return -1; +} + +int +CommandAlias::HandleArgumentCompletion (Args &input, + int &cursor_index, + int &cursor_char_position, + OptionElementVector &opt_element_vector, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + if (IsValid()) + return m_underlying_command_sp->HandleArgumentCompletion(input, + cursor_index, + cursor_char_position, + opt_element_vector, + match_start_point, + max_return_elements, + word_complete, + matches); + return -1; +} + +Options* +CommandAlias::GetOptions() +{ + if (IsValid()) + return m_underlying_command_sp->GetOptions(); + return nullptr; +} + +bool +CommandAlias::Execute(const char *args_string, CommandReturnObject &result) +{ + llvm_unreachable("CommandAlias::Execute is not to be called"); +} + +void +CommandAlias::GetAliasExpansion (StreamString &help_string) +{ + const char* command_name = m_underlying_command_sp->GetCommandName(); + help_string.Printf ("'%s", command_name); + + if (m_option_args_sp) + { + OptionArgVector *options = m_option_args_sp.get(); + for (size_t i = 0; i < options->size(); ++i) + { + OptionArgPair cur_option = (*options)[i]; + std::string opt = cur_option.first; + OptionArgValue value_pair = cur_option.second; + std::string value = value_pair.second; + if (opt.compare("<argument>") == 0) + { + help_string.Printf (" %s", value.c_str()); + } + else + { + help_string.Printf (" %s", opt.c_str()); + if ((value.compare ("<no-argument>") != 0) + && (value.compare ("<need-argument") != 0)) + { + help_string.Printf (" %s", value.c_str()); + } + } + } + } + + help_string.Printf ("'"); +} + +bool +CommandAlias::IsDashDashCommand () +{ + if (m_is_dashdash_alias == eLazyBoolCalculate) + { + m_is_dashdash_alias = eLazyBoolNo; + if (IsValid()) + { + for (const OptionArgPair& opt_arg : *GetOptionArguments()) + { + if (opt_arg.first == "<argument>" && + !opt_arg.second.second.empty() && + llvm::StringRef(opt_arg.second.second).endswith("--")) + { + m_is_dashdash_alias = eLazyBoolYes; + break; + } + } + // if this is a nested alias, it may be adding arguments on top of an already dash-dash alias + if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias()) + m_is_dashdash_alias = (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes : eLazyBoolNo); + } + } + return (m_is_dashdash_alias == eLazyBoolYes); +} + +bool +CommandAlias::IsNestedAlias () +{ + if (GetUnderlyingCommand()) + return GetUnderlyingCommand()->IsAlias(); + return false; +} + +std::pair<lldb::CommandObjectSP, OptionArgVectorSP> +CommandAlias::Desugar () +{ + auto underlying = GetUnderlyingCommand(); + if (!underlying) + return {nullptr,nullptr}; + + if (underlying->IsAlias()) + { + auto desugared = ((CommandAlias*)underlying.get())->Desugar(); + auto options = GetOptionArguments(); + options->insert(options->begin(), desugared.second->begin(), desugared.second->end()); + return {desugared.first,options}; + } + + return {underlying,GetOptionArguments()}; +} + +// allow CommandAlias objects to provide their own help, but fallback to the info +// for the underlying command if no customization has been provided +void +CommandAlias::SetHelp (const char * str) +{ + this->CommandObject::SetHelp(str); + m_did_set_help = true; +} + +void +CommandAlias::SetHelpLong (const char * str) +{ + this->CommandObject::SetHelpLong(str); + m_did_set_help_long = true; +} + +const char* +CommandAlias::GetHelp () +{ + if (!m_cmd_help_short.empty() || m_did_set_help) + return m_cmd_help_short.c_str(); + if (IsValid()) + return m_underlying_command_sp->GetHelp(); + return nullptr; +} + +const char* +CommandAlias::GetHelpLong () +{ + if (!m_cmd_help_long.empty() || m_did_set_help_long) + return m_cmd_help_long.c_str(); + if (IsValid()) + return m_underlying_command_sp->GetHelpLong(); + return nullptr; +} diff --git a/source/Interpreter/CommandHistory.cpp b/source/Interpreter/CommandHistory.cpp index 9d3c814697b0..ff87e528d36f 100644 --- a/source/Interpreter/CommandHistory.cpp +++ b/source/Interpreter/CommandHistory.cpp @@ -15,10 +15,7 @@ using namespace lldb; using namespace lldb_private; - -CommandHistory::CommandHistory () : - m_mutex(Mutex::eMutexTypeRecursive), - m_history() +CommandHistory::CommandHistory() : m_mutex(), m_history() {} CommandHistory::~CommandHistory () @@ -27,21 +24,21 @@ CommandHistory::~CommandHistory () size_t CommandHistory::GetSize () const { - Mutex::Locker locker(m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); return m_history.size(); } bool CommandHistory::IsEmpty () const { - Mutex::Locker locker(m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); return m_history.empty(); } const char* CommandHistory::FindString (const char* input_str) const { - Mutex::Locker locker(m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); if (!input_str) return nullptr; if (input_str[0] != g_repeat_char) @@ -80,7 +77,7 @@ CommandHistory::FindString (const char* input_str) const const char* CommandHistory::GetStringAtIndex (size_t idx) const { - Mutex::Locker locker(m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); if (idx < m_history.size()) return m_history[idx].c_str(); return nullptr; @@ -95,7 +92,7 @@ CommandHistory::operator [] (size_t idx) const const char* CommandHistory::GetRecentmostString () const { - Mutex::Locker locker(m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); if (m_history.empty()) return nullptr; return m_history.back().c_str(); @@ -105,7 +102,7 @@ void CommandHistory::AppendString (const std::string& str, bool reject_if_dupe) { - Mutex::Locker locker(m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); if (reject_if_dupe) { if (!m_history.empty()) @@ -120,7 +117,7 @@ CommandHistory::AppendString (const std::string& str, void CommandHistory::Clear () { - Mutex::Locker locker(m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); m_history.clear(); } @@ -129,7 +126,7 @@ CommandHistory::Dump (Stream& stream, size_t start_idx, size_t stop_idx) const { - Mutex::Locker locker(m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); stop_idx = std::min(stop_idx + 1, m_history.size()); for (size_t counter = start_idx; counter < stop_idx; diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp index fd88f0d6b4be..5d5669f73cbc 100644 --- a/source/Interpreter/CommandInterpreter.cpp +++ b/source/Interpreter/CommandInterpreter.cpp @@ -105,7 +105,7 @@ CommandInterpreter::GetStaticBroadcasterClass () } CommandInterpreter::CommandInterpreter(Debugger &debugger, ScriptLanguage script_language, bool synchronous_execution) - : Broadcaster(&debugger, CommandInterpreter::GetStaticBroadcasterClass().AsCString()), + : Broadcaster(debugger.GetBroadcasterManager(), CommandInterpreter::GetStaticBroadcasterClass().AsCString()), Properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter")))), IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand), m_debugger(debugger), @@ -185,6 +185,9 @@ CommandInterpreter::Initialize () LoadCommandDictionary (); + // An alias arguments vector to reuse - reset it before use... + OptionArgVectorSP alias_arguments_vector_sp (new OptionArgVector); + // Set up some initial aliases. CommandObjectSP cmd_obj_sp = GetCommandSPExact ("quit", false); if (cmd_obj_sp) @@ -195,9 +198,7 @@ CommandInterpreter::Initialize () cmd_obj_sp = GetCommandSPExact ("_regexp-attach",false); if (cmd_obj_sp) - { - AddAlias ("attach", cmd_obj_sp); - } + AddAlias ("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); cmd_obj_sp = GetCommandSPExact ("process detach",false); if (cmd_obj_sp) @@ -214,11 +215,11 @@ CommandInterpreter::Initialize () cmd_obj_sp = GetCommandSPExact ("_regexp-break",false); if (cmd_obj_sp) - AddAlias ("b", cmd_obj_sp); + AddAlias ("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); cmd_obj_sp = GetCommandSPExact ("_regexp-tbreak",false); if (cmd_obj_sp) - AddAlias ("tbreak", cmd_obj_sp); + AddAlias ("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); cmd_obj_sp = GetCommandSPExact ("thread step-inst", false); if (cmd_obj_sp) @@ -239,6 +240,13 @@ CommandInterpreter::Initialize () { AddAlias ("s", cmd_obj_sp); AddAlias ("step", cmd_obj_sp); + CommandAlias *sif_alias = AddAlias ("sif", cmd_obj_sp, "--end-linenumber block --step-in-target %1"); + if (sif_alias) + { + sif_alias->SetHelp("Step through the current block, stopping if you step " + "directly into a function whose name matches the TargetFunctionName."); + sif_alias->SetSyntax("sif <TargetFunctionName>"); + } } cmd_obj_sp = GetCommandSPExact ("thread step-over", false); @@ -269,22 +277,20 @@ CommandInterpreter::Initialize () cmd_obj_sp = GetCommandSPExact ("_regexp-jump",false); if (cmd_obj_sp) { - AddAlias ("j", cmd_obj_sp); - AddAlias ("jump", cmd_obj_sp); + AddAlias ("j", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); + AddAlias ("jump", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); } cmd_obj_sp = GetCommandSPExact ("_regexp-list", false); if (cmd_obj_sp) { - AddAlias ("l", cmd_obj_sp); - AddAlias ("list", cmd_obj_sp); + AddAlias ("l", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); + AddAlias ("list", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); } cmd_obj_sp = GetCommandSPExact ("_regexp-env", false); if (cmd_obj_sp) - { - AddAlias ("env", cmd_obj_sp); - } + AddAlias ("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); cmd_obj_sp = GetCommandSPExact ("memory read", false); if (cmd_obj_sp) @@ -292,15 +298,15 @@ CommandInterpreter::Initialize () cmd_obj_sp = GetCommandSPExact ("_regexp-up", false); if (cmd_obj_sp) - AddAlias ("up", cmd_obj_sp); + AddAlias ("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); cmd_obj_sp = GetCommandSPExact ("_regexp-down", false); if (cmd_obj_sp) - AddAlias ("down", cmd_obj_sp); + AddAlias ("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); cmd_obj_sp = GetCommandSPExact ("_regexp-display", false); if (cmd_obj_sp) - AddAlias ("display", cmd_obj_sp); + AddAlias ("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); cmd_obj_sp = GetCommandSPExact ("disassemble", false); if (cmd_obj_sp) @@ -314,11 +320,11 @@ CommandInterpreter::Initialize () cmd_obj_sp = GetCommandSPExact ("_regexp-undisplay", false); if (cmd_obj_sp) - AddAlias ("undisplay", cmd_obj_sp); + AddAlias ("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); cmd_obj_sp = GetCommandSPExact ("_regexp-bt", false); if (cmd_obj_sp) - AddAlias ("bt", cmd_obj_sp); + AddAlias ("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); cmd_obj_sp = GetCommandSPExact ("target create", false); if (cmd_obj_sp) @@ -329,23 +335,22 @@ CommandInterpreter::Initialize () AddAlias ("image", cmd_obj_sp); - OptionArgVectorSP alias_arguments_vector_sp (new OptionArgVector); - + alias_arguments_vector_sp.reset(new OptionArgVector); + cmd_obj_sp = GetCommandSPExact ("expression", false); if (cmd_obj_sp) { - ProcessAliasOptionsArgs (cmd_obj_sp, "--", alias_arguments_vector_sp); - AddAlias ("p", cmd_obj_sp); - AddAlias ("print", cmd_obj_sp); - AddAlias ("call", cmd_obj_sp); - AddOrReplaceAliasOptions ("p", alias_arguments_vector_sp); - AddOrReplaceAliasOptions ("print", alias_arguments_vector_sp); - AddOrReplaceAliasOptions ("call", alias_arguments_vector_sp); - - alias_arguments_vector_sp.reset (new OptionArgVector); - ProcessAliasOptionsArgs (cmd_obj_sp, "-O -- ", alias_arguments_vector_sp); - AddAlias ("po", cmd_obj_sp); - AddOrReplaceAliasOptions ("po", alias_arguments_vector_sp); + AddAlias ("p", cmd_obj_sp, "--")->SetHelpLong(""); + AddAlias ("print", cmd_obj_sp, "--")->SetHelpLong(""); + AddAlias ("call", cmd_obj_sp, "--")->SetHelpLong(""); + if (auto po = AddAlias ("po", cmd_obj_sp, "-O --")) + { + po->SetHelp("Evaluate an expression on the current thread. Displays any returned value with formatting " + "controlled by the type's author."); + po->SetHelpLong(""); + } + AddAlias("parray", cmd_obj_sp, "--element-count %1 --")->SetHelpLong(""); + AddAlias("poarray", cmd_obj_sp, "--object-description --element-count %1 --")->SetHelpLong(""); } cmd_obj_sp = GetCommandSPExact ("process kill", false); @@ -359,26 +364,23 @@ CommandInterpreter::Initialize () { alias_arguments_vector_sp.reset (new OptionArgVector); #if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) - ProcessAliasOptionsArgs (cmd_obj_sp, "--", alias_arguments_vector_sp); + AddAlias ("r", cmd_obj_sp, "--"); + AddAlias ("run", cmd_obj_sp, "--"); #else #if defined(__APPLE__) std::string shell_option; shell_option.append("--shell-expand-args"); shell_option.append(" true"); shell_option.append(" --"); - ProcessAliasOptionsArgs (cmd_obj_sp, shell_option.c_str(), alias_arguments_vector_sp); + AddAlias ("r", cmd_obj_sp, "--shell-expand-args true --"); + AddAlias ("run", cmd_obj_sp, "--shell-expand-args true --"); #else - std::string shell_option; - shell_option.append("--shell="); - shell_option.append(HostInfo::GetDefaultShell().GetPath()); - shell_option.append(" --"); - ProcessAliasOptionsArgs (cmd_obj_sp, shell_option.c_str(), alias_arguments_vector_sp); + StreamString defaultshell; + defaultshell.Printf("--shell=%s --", HostInfo::GetDefaultShell().GetPath().c_str()); + AddAlias ("r", cmd_obj_sp, defaultshell.GetData()); + AddAlias ("run", cmd_obj_sp, defaultshell.GetData()); #endif #endif - AddAlias ("r", cmd_obj_sp); - AddAlias ("run", cmd_obj_sp); - AddOrReplaceAliasOptions ("r", alias_arguments_vector_sp); - AddOrReplaceAliasOptions ("run", alias_arguments_vector_sp); } cmd_obj_sp = GetCommandSPExact ("target symbols add", false); @@ -390,10 +392,7 @@ CommandInterpreter::Initialize () cmd_obj_sp = GetCommandSPExact ("breakpoint set", false); if (cmd_obj_sp) { - alias_arguments_vector_sp.reset (new OptionArgVector); - ProcessAliasOptionsArgs (cmd_obj_sp, "--func-regex %1", alias_arguments_vector_sp); - AddAlias ("rbreak", cmd_obj_sp); - AddOrReplaceAliasOptions("rbreak", alias_arguments_vector_sp); + AddAlias ("rbreak", cmd_obj_sp, "--func-regex %1"); } } @@ -466,22 +465,26 @@ CommandInterpreter::LoadCommandDictionary () {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$", "breakpoint set --name '%1'"}}; size_t num_regexes = llvm::array_lengthof(break_regexes); - - std::unique_ptr<CommandObjectRegexCommand> - break_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "_regexp-break", - "Set a breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.\n", - "\n_regexp-break <filename>:<linenum> # _regexp-break main.c:12 // Break on line 12 of main.c\n" - "_regexp-break <linenum> # _regexp-break 12 // Break on line 12 of current file\n" - "_regexp-break <address> # _regexp-break 0x1234000 // Break on address 0x1234000\n" - "_regexp-break <name> # _regexp-break main // Break in 'main' after the prologue\n" - "_regexp-break &<name> # _regexp-break &main // Break on the first instruction in 'main'\n" - "_regexp-break <module>`<name> # _regexp-break libc.so`malloc // Break in 'malloc' only in the 'libc.so' shared library\n" - "_regexp-break /<source-regex>/ # _regexp-break /break here/ // Break on all lines that match the regular expression 'break here' in the current file.\n", - 2, - CommandCompletions::eSymbolCompletion | - CommandCompletions::eSourceFileCompletion, - false)); + + std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_ap(new CommandObjectRegexCommand( + *this, "_regexp-break", "Set a breakpoint using one of several shorthand formats.\n", + "\n" + "_regexp-break <filename>:<linenum>\n" + " main.c:12 // Break at line 12 of main.c\n\n" + "_regexp-break <linenum>\n" + " 12 // Break at line 12 of current file\n\n" + "_regexp-break 0x<address>\n" + " 0x1234000 // Break at address 0x1234000\n\n" + "_regexp-break <name>\n" + " main // Break in 'main' after the prologue\n\n" + "_regexp-break &<name>\n" + " &main // Break at first instruction in 'main'\n\n" + "_regexp-break <module>`<name>\n" + " libc.so`malloc // Break in 'malloc' from 'libc.so'\n\n" + "_regexp-break /<source-regex>/\n" + " /break here/ // Break on source lines in current file\n" + " // containing text 'break here'.\n", + 2, CommandCompletions::eSymbolCompletion | CommandCompletions::eSourceFileCompletion, false)); if (break_regex_cmd_ap.get()) { @@ -501,15 +504,25 @@ CommandInterpreter::LoadCommandDictionary () } } - std::unique_ptr<CommandObjectRegexCommand> - tbreak_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "_regexp-tbreak", - "Set a one shot breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.", - "_regexp-tbreak [<filename>:<linenum>]\n_regexp-break [<linenum>]\n_regexp-break [<address>]\n_regexp-break <...>", - 2, - CommandCompletions::eSymbolCompletion | - CommandCompletions::eSourceFileCompletion, - false)); + std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_ap(new CommandObjectRegexCommand( + *this, "_regexp-tbreak", "Set a one-shot breakpoint using one of several shorthand formats.\n", + "\n" + "_regexp-break <filename>:<linenum>\n" + " main.c:12 // Break at line 12 of main.c\n\n" + "_regexp-break <linenum>\n" + " 12 // Break at line 12 of current file\n\n" + "_regexp-break 0x<address>\n" + " 0x1234000 // Break at address 0x1234000\n\n" + "_regexp-break <name>\n" + " main // Break in 'main' after the prologue\n\n" + "_regexp-break &<name>\n" + " &main // Break at first instruction in 'main'\n\n" + "_regexp-break <module>`<name>\n" + " libc.so`malloc // Break in 'malloc' from 'libc.so'\n\n" + "_regexp-break /<source-regex>/\n" + " /break here/ // Break on source lines in current file\n" + " // containing text 'break here'.\n", + 2, CommandCompletions::eSymbolCompletion | CommandCompletions::eSourceFileCompletion, false)); if (tbreak_regex_cmd_ap.get()) { @@ -534,14 +547,9 @@ CommandInterpreter::LoadCommandDictionary () } } - std::unique_ptr<CommandObjectRegexCommand> - attach_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "_regexp-attach", - "Attach to a process id if in decimal, otherwise treat the argument as a process name to attach to.", - "_regexp-attach [<pid>]\n_regexp-attach [<process-name>]", - 2, - 0, - false)); + std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_ap( + new CommandObjectRegexCommand(*this, "_regexp-attach", "Attach to process by ID or name.", + "_regexp-attach <pid> | <process-name>", 2, 0, false)); if (attach_regex_cmd_ap.get()) { if (attach_regex_cmd_ap->AddRegexCommand("^([0-9]+)[[:space:]]*$", "process attach --pid %1") && @@ -553,15 +561,11 @@ CommandInterpreter::LoadCommandDictionary () m_command_dict[attach_regex_cmd_sp->GetCommandName ()] = attach_regex_cmd_sp; } } - - std::unique_ptr<CommandObjectRegexCommand> - down_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "_regexp-down", - "Go down \"n\" frames in the stack (1 frame by default).", - "_regexp-down [n]", - 2, - 0, - false)); + + std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_ap(new CommandObjectRegexCommand( + *this, "_regexp-down", "Select a newer stack frame. Defaults to moving one frame, a numeric argument can " + "specify an arbitrary number.", + "_regexp-down [<count>]", 2, 0, false)); if (down_regex_cmd_ap.get()) { if (down_regex_cmd_ap->AddRegexCommand("^$", "frame select -r -1") && @@ -571,15 +575,11 @@ CommandInterpreter::LoadCommandDictionary () m_command_dict[down_regex_cmd_sp->GetCommandName ()] = down_regex_cmd_sp; } } - - std::unique_ptr<CommandObjectRegexCommand> - up_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "_regexp-up", - "Go up \"n\" frames in the stack (1 frame by default).", - "_regexp-up [n]", - 2, - 0, - false)); + + std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_ap( + new CommandObjectRegexCommand(*this, "_regexp-up", "Select an older stack frame. Defaults to moving one " + "frame, a numeric argument can specify an arbitrary number.", + "_regexp-up [<count>]", 2, 0, false)); if (up_regex_cmd_ap.get()) { if (up_regex_cmd_ap->AddRegexCommand("^$", "frame select -r 1") && @@ -590,14 +590,9 @@ CommandInterpreter::LoadCommandDictionary () } } - std::unique_ptr<CommandObjectRegexCommand> - display_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "_regexp-display", - "Add an expression evaluation stop-hook.", - "_regexp-display expression", - 2, - 0, - false)); + std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_ap(new CommandObjectRegexCommand( + *this, "_regexp-display", "Evaluate an expression at every stop (see 'help target stop-hook'.)", + "_regexp-display expression", 2, 0, false)); if (display_regex_cmd_ap.get()) { if (display_regex_cmd_ap->AddRegexCommand("^(.+)$", "target stop-hook add -o \"expr -- %1\"")) @@ -607,14 +602,9 @@ CommandInterpreter::LoadCommandDictionary () } } - std::unique_ptr<CommandObjectRegexCommand> - undisplay_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "_regexp-undisplay", - "Remove an expression evaluation stop-hook.", - "_regexp-undisplay stop-hook-number", - 2, - 0, - false)); + std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_ap(new CommandObjectRegexCommand( + *this, "_regexp-undisplay", "Stop displaying expression at every stop (specified by stop-hook index.)", + "_regexp-undisplay stop-hook-number", 2, 0, false)); if (undisplay_regex_cmd_ap.get()) { if (undisplay_regex_cmd_ap->AddRegexCommand("^([0-9]+)$", "target stop-hook delete %1")) @@ -624,14 +614,10 @@ CommandInterpreter::LoadCommandDictionary () } } - std::unique_ptr<CommandObjectRegexCommand> - connect_gdb_remote_cmd_ap(new CommandObjectRegexCommand (*this, - "gdb-remote", - "Connect to a remote GDB server. If no hostname is provided, localhost is assumed.", - "gdb-remote [<hostname>:]<portnum>", - 2, - 0, - false)); + std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_ap(new CommandObjectRegexCommand( + *this, "gdb-remote", + "Connect to a process via remote GDB server. If no host is specifed, localhost is assumed.", + "gdb-remote [<hostname>:]<portnum>", 2, 0, false)); if (connect_gdb_remote_cmd_ap.get()) { if (connect_gdb_remote_cmd_ap->AddRegexCommand("^([^:]+:[[:digit:]]+)$", "process connect --plugin gdb-remote connect://%1") && @@ -642,14 +628,10 @@ CommandInterpreter::LoadCommandDictionary () } } - std::unique_ptr<CommandObjectRegexCommand> - connect_kdp_remote_cmd_ap(new CommandObjectRegexCommand (*this, - "kdp-remote", - "Connect to a remote KDP server. udp port 41139 is the default port number.", - "kdp-remote <hostname>[:<portnum>]", - 2, - 0, - false)); + std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_ap(new CommandObjectRegexCommand( + *this, "kdp-remote", + "Connect to a process via remote KDP server. If no UDP port is specified, port 41139 is assumed.", + "kdp-remote <hostname>[:<portnum>]", 2, 0, false)); if (connect_kdp_remote_cmd_ap.get()) { if (connect_kdp_remote_cmd_ap->AddRegexCommand("^([^:]+:[[:digit:]]+)$", "process connect --plugin kdp-remote udp://%1") && @@ -660,14 +642,10 @@ CommandInterpreter::LoadCommandDictionary () } } - std::unique_ptr<CommandObjectRegexCommand> - bt_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "_regexp-bt", - "Show a backtrace. An optional argument is accepted; if that argument is a number, it specifies the number of frames to display. If that argument is 'all', full backtraces of all threads are displayed.", - "bt [<digit>|all]", - 2, - 0, - false)); + std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_ap(new CommandObjectRegexCommand( + *this, "_regexp-bt", "Show the current thread's call stack. Any numeric argument displays at most that many " + "frames. The argument 'all' displays all threads.", + "bt [<digit> | all]", 2, 0, false)); if (bt_regex_cmd_ap.get()) { // accept but don't document "bt -c <number>" -- before bt was a regex command if you wanted to backtrace @@ -683,14 +661,16 @@ CommandInterpreter::LoadCommandDictionary () } } - std::unique_ptr<CommandObjectRegexCommand> - list_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "_regexp-list", - "Implements the GDB 'list' command in all of its forms except FILE:FUNCTION and maps them to the appropriate 'source list' commands.", - "_regexp-list [<line>]\n_regexp-list [<file>:<line>]\n_regexp-list [<file>:<line>]", - 2, - CommandCompletions::eSourceFileCompletion, - false)); + std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_ap(new CommandObjectRegexCommand( + *this, "_regexp-list", "List relevant source code using one of several shorthand formats.", + "\n" + "_regexp-list <file>:<line> // List around specific file/line\n" + "_regexp-list <line> // List current file around specified line\n" + "_regexp-list <function-name> // List specified function\n" + "_regexp-list 0x<address> // List around specified address\n" + "_regexp-list -[<count>] // List previous <count> lines\n" + "_regexp-list // List subsequent lines", + 2, CommandCompletions::eSourceFileCompletion, false)); if (list_regex_cmd_ap.get()) { if (list_regex_cmd_ap->AddRegexCommand("^([0-9]+)[[:space:]]*$", "source list --line %1") && @@ -706,14 +686,12 @@ CommandInterpreter::LoadCommandDictionary () } } - std::unique_ptr<CommandObjectRegexCommand> - env_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "_regexp-env", - "Implements a shortcut to viewing and setting environment variables.", - "_regexp-env\n_regexp-env FOO=BAR", - 2, - 0, - false)); + std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_ap( + new CommandObjectRegexCommand(*this, "_regexp-env", "Shorthand for viewing and setting environment variables.", + "\n" + "_regexp-env // Show enrivonment\n" + "_regexp-env <name>=<value> // Set an environment variable", + 2, 0, false)); if (env_regex_cmd_ap.get()) { if (env_regex_cmd_ap->AddRegexCommand("^$", "settings show target.env-vars") && @@ -724,17 +702,14 @@ CommandInterpreter::LoadCommandDictionary () } } - std::unique_ptr<CommandObjectRegexCommand> - jump_regex_cmd_ap(new CommandObjectRegexCommand (*this, - "_regexp-jump", - "Sets the program counter to a new address.", - "_regexp-jump [<line>]\n" - "_regexp-jump [<+-lineoffset>]\n" - "_regexp-jump [<file>:<line>]\n" - "_regexp-jump [*<addr>]\n", - 2, - 0, - false)); + std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_ap( + new CommandObjectRegexCommand(*this, "_regexp-jump", "Set the program counter to a new address.", + "\n" + "_regexp-jump <line>\n" + "_regexp-jump +<line-offset> | -<line-offset>\n" + "_regexp-jump <file>:<line>\n" + "_regexp-jump *<addr>\n", + 2, 0, false)); if (jump_regex_cmd_ap.get()) { if (jump_regex_cmd_ap->AddRegexCommand("^\\*(.*)$", "thread jump --addr %1") && @@ -753,11 +728,11 @@ int CommandInterpreter::GetCommandNamesMatchingPartialString (const char *cmd_str, bool include_aliases, StringList &matches) { - CommandObject::AddNamesMatchingPartialString (m_command_dict, cmd_str, matches); + AddNamesMatchingPartialString (m_command_dict, cmd_str, matches); if (include_aliases) { - CommandObject::AddNamesMatchingPartialString (m_alias_dict, cmd_str, matches); + AddNamesMatchingPartialString (m_alias_dict, cmd_str, matches); } return matches.GetSize(); @@ -780,9 +755,9 @@ CommandInterpreter::GetCommandSP (const char *cmd_cstr, bool include_aliases, bo if (include_aliases && HasAliases()) { - pos = m_alias_dict.find(cmd); - if (pos != m_alias_dict.end()) - command_sp = pos->second; + auto alias_pos = m_alias_dict.find(cmd); + if (alias_pos != m_alias_dict.end()) + command_sp = alias_pos->second; } if (HasUserCommands()) @@ -811,7 +786,7 @@ CommandInterpreter::GetCommandSP (const char *cmd_cstr, bool include_aliases, bo if (HasCommands()) { - num_cmd_matches = CommandObject::AddNamesMatchingPartialString (m_command_dict, cmd_cstr, *matches); + num_cmd_matches = AddNamesMatchingPartialString (m_command_dict, cmd_cstr, *matches); } if (num_cmd_matches == 1) @@ -824,21 +799,21 @@ CommandInterpreter::GetCommandSP (const char *cmd_cstr, bool include_aliases, bo if (include_aliases && HasAliases()) { - num_alias_matches = CommandObject::AddNamesMatchingPartialString (m_alias_dict, cmd_cstr, *matches); + num_alias_matches = AddNamesMatchingPartialString (m_alias_dict, cmd_cstr, *matches); } if (num_alias_matches == 1) { cmd.assign(matches->GetStringAtIndex (num_cmd_matches)); - pos = m_alias_dict.find(cmd); - if (pos != m_alias_dict.end()) - alias_match_sp = pos->second; + auto alias_pos = m_alias_dict.find(cmd); + if (alias_pos != m_alias_dict.end()) + alias_match_sp = alias_pos->second; } if (HasUserCommands()) { - num_user_matches = CommandObject::AddNamesMatchingPartialString (m_user_dict, cmd_cstr, *matches); + num_user_matches = AddNamesMatchingPartialString (m_user_dict, cmd_cstr, *matches); } if (num_user_matches == 1) @@ -874,6 +849,9 @@ CommandInterpreter::GetCommandSP (const char *cmd_cstr, bool include_aliases, bo bool CommandInterpreter::AddCommand (const char *name, const lldb::CommandObjectSP &cmd_sp, bool can_replace) { + if (cmd_sp.get()) + assert((this == &cmd_sp->GetCommandInterpreter()) && "tried to add a CommandObject from a different interpreter"); + if (name && name[0]) { std::string name_sstr(name); @@ -893,9 +871,11 @@ CommandInterpreter::AddUserCommand (std::string name, const lldb::CommandObjectSP &cmd_sp, bool can_replace) { + if (cmd_sp.get()) + assert((this == &cmd_sp->GetCommandInterpreter()) && "tried to add a CommandObject from a different interpreter"); + if (!name.empty()) { - const char* name_cstr = name.c_str(); // do not allow replacement of internal commands @@ -1009,59 +989,6 @@ CommandInterpreter::CommandExists (const char *cmd) } bool -CommandInterpreter::ProcessAliasOptionsArgs (lldb::CommandObjectSP &cmd_obj_sp, - const char *options_args, - OptionArgVectorSP &option_arg_vector_sp) -{ - bool success = true; - OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); - - if (!options_args || (strlen (options_args) < 1)) - return true; - - std::string options_string (options_args); - Args args (options_args); - CommandReturnObject result; - // Check to see if the command being aliased can take any command options. - Options *options = cmd_obj_sp->GetOptions (); - if (options) - { - // See if any options were specified as part of the alias; if so, handle them appropriately. - options->NotifyOptionParsingStarting (); - args.Unshift ("dummy_arg"); - args.ParseAliasOptions (*options, result, option_arg_vector, options_string); - args.Shift (); - if (result.Succeeded()) - options->VerifyPartialOptions (result); - if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted) - { - result.AppendError ("Unable to create requested alias.\n"); - return false; - } - } - - if (!options_string.empty()) - { - if (cmd_obj_sp->WantsRawCommandString ()) - option_arg_vector->push_back (OptionArgPair ("<argument>", - OptionArgValue (-1, - options_string))); - else - { - const size_t argc = args.GetArgumentCount(); - for (size_t i = 0; i < argc; ++i) - if (strcmp (args.GetArgumentAtIndex (i), "") != 0) - option_arg_vector->push_back - (OptionArgPair ("<argument>", - OptionArgValue (-1, - std::string (args.GetArgumentAtIndex (i))))); - } - } - - return success; -} - -bool CommandInterpreter::GetAliasFullName (const char *cmd, std::string &full_name) { bool exact_match = (m_alias_dict.find(cmd) != m_alias_dict.end()); @@ -1074,7 +1001,7 @@ CommandInterpreter::GetAliasFullName (const char *cmd, std::string &full_name) { StringList matches; size_t num_alias_matches; - num_alias_matches = CommandObject::AddNamesMatchingPartialString (m_alias_dict, cmd, matches); + num_alias_matches = AddNamesMatchingPartialString (m_alias_dict, cmd, matches); if (num_alias_matches == 1) { // Make sure this isn't shadowing a command in the regular command space: @@ -1107,17 +1034,32 @@ CommandInterpreter::UserCommandExists (const char *cmd) return m_user_dict.find(cmd) != m_user_dict.end(); } -void -CommandInterpreter::AddAlias (const char *alias_name, CommandObjectSP& command_obj_sp) +CommandAlias* +CommandInterpreter::AddAlias (const char *alias_name, + lldb::CommandObjectSP& command_obj_sp, + const char *args_string) { - command_obj_sp->SetIsAlias (true); - m_alias_dict[alias_name] = command_obj_sp; + if (command_obj_sp.get()) + assert((this == &command_obj_sp->GetCommandInterpreter()) && "tried to add a CommandObject from a different interpreter"); + + std::unique_ptr<CommandAlias> command_alias_up(new CommandAlias(*this, + command_obj_sp, + args_string, + alias_name)); + + if (command_alias_up && command_alias_up->IsValid()) + { + m_alias_dict[alias_name] = CommandObjectSP(command_alias_up.get()); + return command_alias_up.release(); + } + + return nullptr; } bool CommandInterpreter::RemoveAlias (const char *alias_name) { - CommandObject::CommandMap::iterator pos = m_alias_dict.find(alias_name); + auto pos = m_alias_dict.find(alias_name); if (pos != m_alias_dict.end()) { m_alias_dict.erase(pos); @@ -1154,56 +1096,6 @@ CommandInterpreter::RemoveUser (const char *alias_name) } void -CommandInterpreter::GetAliasHelp (const char *alias_name, const char *command_name, StreamString &help_string) -{ - help_string.Printf ("'%s", command_name); - OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name); - - if (option_arg_vector_sp) - { - OptionArgVector *options = option_arg_vector_sp.get(); - for (size_t i = 0; i < options->size(); ++i) - { - OptionArgPair cur_option = (*options)[i]; - std::string opt = cur_option.first; - OptionArgValue value_pair = cur_option.second; - std::string value = value_pair.second; - if (opt.compare("<argument>") == 0) - { - help_string.Printf (" %s", value.c_str()); - } - else - { - help_string.Printf (" %s", opt.c_str()); - if ((value.compare ("<no-argument>") != 0) - && (value.compare ("<need-argument") != 0)) - { - help_string.Printf (" %s", value.c_str()); - } - } - } - } - - help_string.Printf ("'"); -} - -size_t -CommandInterpreter::FindLongestCommandWord (CommandObject::CommandMap &dict) -{ - CommandObject::CommandMap::const_iterator pos; - CommandObject::CommandMap::const_iterator end = dict.end(); - size_t max_len = 0; - - for (pos = dict.begin(); pos != end; ++pos) - { - size_t len = pos->first.size(); - if (max_len < len) - max_len = len; - } - return max_len; -} - -void CommandInterpreter::GetHelp (CommandReturnObject &result, uint32_t cmd_types) { @@ -1241,17 +1133,10 @@ CommandInterpreter::GetHelp (CommandReturnObject &result, result.AppendMessage(""); max_len = FindLongestCommandWord (m_alias_dict); - for (pos = m_alias_dict.begin(); pos != m_alias_dict.end(); ++pos) + for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end(); ++alias_pos) { - StreamString sstr; - StreamString translation_and_help; - std::string entry_name = pos->first; - std::string second_entry = pos->second.get()->GetCommandName(); - GetAliasHelp (pos->first.c_str(), pos->second->GetCommandName(), sstr); - - translation_and_help.Printf ("(%s) %s", sstr.GetData(), pos->second->GetHelp()); - OutputFormattedHelpText (result.GetOutputStream(), pos->first.c_str(), "--", - translation_and_help.GetData(), max_len); + OutputFormattedHelpText (result.GetOutputStream(), alias_pos->first.c_str(), "--", alias_pos->second->GetHelp(), + max_len); } result.AppendMessage(""); } @@ -1451,15 +1336,17 @@ CommandInterpreter::BuildAliasResult (const char *alias_name, alias_cmd_obj = GetCommandObject (alias_name); StreamString result_str; - if (alias_cmd_obj) + if (alias_cmd_obj && alias_cmd_obj->IsAlias()) { + std::pair<CommandObjectSP, OptionArgVectorSP> desugared = ((CommandAlias*)alias_cmd_obj)->Desugar(); + OptionArgVectorSP option_arg_vector_sp = desugared.second; + alias_cmd_obj = desugared.first.get(); std::string alias_name_str = alias_name; if ((cmd_args.GetArgumentCount() == 0) || (alias_name_str.compare (cmd_args.GetArgumentAtIndex(0)) != 0)) cmd_args.Unshift (alias_name); result_str.Printf ("%s", alias_cmd_obj->GetCommandName ()); - OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name); if (option_arg_vector_sp.get()) { @@ -1617,6 +1504,7 @@ CommandInterpreter::PreprocessCommand (std::string &command) break; case eExpressionResultUnavailable: error.SetErrorStringWithFormat ("expression error fetching result for the expression '%s'", expr_str.c_str()); + break; case eExpressionCompleted: break; case eExpressionDiscarded: @@ -2085,38 +1973,18 @@ CommandInterpreter::Confirm (const char *message, bool default_answer) return confirm->GetResponse(); } -OptionArgVectorSP -CommandInterpreter::GetAliasOptions (const char *alias_name) +CommandAlias* +CommandInterpreter::GetAlias (const char *alias_name) { - OptionArgMap::iterator pos; OptionArgVectorSP ret_val; std::string alias (alias_name); - if (HasAliasOptions()) - { - pos = m_alias_options.find (alias); - if (pos != m_alias_options.end()) - ret_val = pos->second; - } - - return ret_val; -} - -void -CommandInterpreter::RemoveAliasOptions (const char *alias_name) -{ - OptionArgMap::iterator pos = m_alias_options.find(alias_name); - if (pos != m_alias_options.end()) - { - m_alias_options.erase (pos); - } -} - -void -CommandInterpreter::AddOrReplaceAliasOptions (const char *alias_name, OptionArgVectorSP &option_arg_vector_sp) -{ - m_alias_options[alias_name] = option_arg_vector_sp; + auto pos = m_alias_dict.find(alias); + if (pos != m_alias_dict.end()) + return (CommandAlias*)pos->second.get(); + + return nullptr; } bool @@ -2140,7 +2008,7 @@ CommandInterpreter::HasUserCommands () bool CommandInterpreter::HasAliasOptions () { - return (!m_alias_options.empty()); + return HasAliases(); } void @@ -2150,7 +2018,7 @@ CommandInterpreter::BuildAliasCommandArgs (CommandObject *alias_cmd_obj, std::string &raw_input_string, CommandReturnObject &result) { - OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name); + OptionArgVectorSP option_arg_vector_sp = GetAlias(alias_name)->GetOptionArguments(); bool wants_raw_input = alias_cmd_obj->WantsRawCommandString(); @@ -2311,12 +2179,44 @@ CommandInterpreter::SourceInitFile (bool in_cwd, CommandReturnObject &result) FileSpec init_file; if (in_cwd) { - // In the current working directory we don't load any program specific - // .lldbinit files, we only look for a "./.lldbinit" file. - if (m_skip_lldbinit_files) - return; + ExecutionContext exe_ctx(GetExecutionContext()); + Target *target = exe_ctx.GetTargetPtr(); + if (target) + { + // In the current working directory we don't load any program specific + // .lldbinit files, we only look for a ".lldbinit" file. + if (m_skip_lldbinit_files) + return; - init_file.SetFile ("./.lldbinit", true); + LoadCWDlldbinitFile should_load = target->TargetProperties::GetLoadCWDlldbinitFile (); + if (should_load == eLoadCWDlldbinitWarn) + { + FileSpec dot_lldb (".lldbinit", true); + llvm::SmallString<64> home_dir_path; + llvm::sys::path::home_directory (home_dir_path); + FileSpec homedir_dot_lldb (home_dir_path.c_str(), false); + homedir_dot_lldb.AppendPathComponent (".lldbinit"); + homedir_dot_lldb.ResolvePath (); + if (dot_lldb.Exists () + && dot_lldb.GetDirectory() != homedir_dot_lldb.GetDirectory()) + { + result.AppendErrorWithFormat ( + "There is a .lldbinit file in the current directory which is not being read.\n" + "To silence this warning without sourcing in the local .lldbinit,\n" + "add the following to the lldbinit file in your home directory:\n" + " settings set target.load-cwd-lldbinit false\n" + "To allow lldb to source .lldbinit files in the current working directory,\n" + "set the value of this variable to true. Only do so if you understand and\n" + "accept the security risk."); + result.SetStatus (eReturnStatusFailed); + return; + } + } + else if (should_load == eLoadCWDlldbinitTrue) + { + init_file.SetFile ("./.lldbinit", true); + } + } } else { @@ -2856,54 +2756,63 @@ CommandInterpreter::OutputHelpText (Stream &strm, } void -CommandInterpreter::FindCommandsForApropos (const char *search_word, StringList &commands_found, - StringList &commands_help, bool search_builtin_commands, bool search_user_commands) +CommandInterpreter::FindCommandsForApropos (const char *search_word, + StringList &commands_found, + StringList &commands_help, + CommandObject::CommandMap &command_map) { CommandObject::CommandMap::const_iterator pos; - - if (search_builtin_commands) + + for (pos = command_map.begin(); pos != command_map.end(); ++pos) { - for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) + const char *command_name = pos->first.c_str(); + CommandObject *cmd_obj = pos->second.get(); + + const bool search_short_help = true; + const bool search_long_help = false; + const bool search_syntax = false; + const bool search_options = false; + if (strcasestr(command_name, search_word) || + cmd_obj->HelpTextContainsWord (search_word, + search_short_help, + search_long_help, + search_syntax, + search_options)) + { + commands_found.AppendString (cmd_obj->GetCommandName()); + commands_help.AppendString (cmd_obj->GetHelp()); + } + + if (cmd_obj->IsMultiwordObject()) { - const char *command_name = pos->first.c_str(); - CommandObject *cmd_obj = pos->second.get(); - - if (cmd_obj->HelpTextContainsWord (search_word)) - { - commands_found.AppendString (command_name); - commands_help.AppendString (cmd_obj->GetHelp()); - } - - if (cmd_obj->IsMultiwordObject()) - cmd_obj->AproposAllSubCommands (command_name, - search_word, - commands_found, - commands_help); - + CommandObjectMultiword *cmd_multiword = cmd_obj->GetAsMultiwordCommand(); + FindCommandsForApropos(search_word, + commands_found, + commands_help, + cmd_multiword->GetSubcommandDictionary()); } } +} + + +void +CommandInterpreter::FindCommandsForApropos (const char *search_word, + StringList &commands_found, + StringList &commands_help, + bool search_builtin_commands, + bool search_user_commands, + bool search_alias_commands) +{ + CommandObject::CommandMap::const_iterator pos; + + if (search_builtin_commands) + FindCommandsForApropos(search_word, commands_found, commands_help, m_command_dict); if (search_user_commands) - { - for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) - { - const char *command_name = pos->first.c_str(); - CommandObject *cmd_obj = pos->second.get(); - - if (cmd_obj->HelpTextContainsWord (search_word)) - { - commands_found.AppendString (command_name); - commands_help.AppendString (cmd_obj->GetHelp()); - } + FindCommandsForApropos(search_word, commands_found, commands_help, m_user_dict); - if (cmd_obj->IsMultiwordObject()) - cmd_obj->AproposAllSubCommands (command_name, - search_word, - commands_found, - commands_help); - - } - } + if (search_alias_commands) + FindCommandsForApropos(search_word, commands_found, commands_help, m_alias_dict); } void @@ -3240,8 +3149,12 @@ CommandInterpreter::ResolveCommandImpl(std::string &command_line, CommandReturnO if (cmd_obj == nullptr) { std::string full_name; - if (GetAliasFullName(next_word.c_str(), full_name)) + bool is_alias = GetAliasFullName(next_word.c_str(), full_name); + cmd_obj = GetCommandObject(next_word.c_str(), &matches); + bool is_real_command = (is_alias == false) || (cmd_obj != nullptr && cmd_obj->IsAlias() == false); + if (!is_real_command) { + matches.Clear(); std::string alias_result; cmd_obj = BuildAliasResult(full_name.c_str(), scratch_command, alias_result, result); revised_command_line.Printf("%s", alias_result.c_str()); @@ -3253,7 +3166,8 @@ CommandInterpreter::ResolveCommandImpl(std::string &command_line, CommandReturnO } else { - cmd_obj = GetCommandObject(next_word.c_str(), &matches); + if (!cmd_obj) + cmd_obj = GetCommandObject(next_word.c_str(), &matches); if (cmd_obj) { actual_cmd_name_len += strlen(cmd_obj->GetCommandName()); diff --git a/source/Interpreter/CommandObject.cpp b/source/Interpreter/CommandObject.cpp index 616d3e38acbb..75e42925406b 100644 --- a/source/Interpreter/CommandObject.cpp +++ b/source/Interpreter/CommandObject.cpp @@ -53,7 +53,6 @@ CommandObject::CommandObject m_cmd_help_short (), m_cmd_help_long (), m_cmd_syntax (), - m_is_alias (false), m_flags (flags), m_arguments(), m_deprecated_command_override_callback (nullptr), @@ -89,12 +88,12 @@ CommandObject::GetSyntax () { StreamString syntax_str; syntax_str.Printf ("%s", GetCommandName()); - if (GetOptions() != nullptr) + if (!IsDashDashCommand() && GetOptions() != nullptr) syntax_str.Printf (" <cmd-options>"); if (m_arguments.size() > 0) { syntax_str.Printf (" "); - if (WantsRawCommandString() && GetOptions() && GetOptions()->NumCommandOptions()) + if (!IsDashDashCommand() && WantsRawCommandString() && GetOptions() && GetOptions()->NumCommandOptions()) syntax_str.Printf("-- "); GetFormattedCommandArguments (syntax_str); } @@ -119,25 +118,19 @@ CommandObject::SetCommandName (const char *name) void CommandObject::SetHelp (const char *cstr) { - m_cmd_help_short = cstr; -} - -void -CommandObject::SetHelp (std::string str) -{ - m_cmd_help_short = str; + if (cstr) + m_cmd_help_short = cstr; + else + m_cmd_help_short.assign(""); } void CommandObject::SetHelpLong (const char *cstr) { - m_cmd_help_long = cstr; -} - -void -CommandObject::SetHelpLong (std::string str) -{ - m_cmd_help_long = str; + if (cstr) + m_cmd_help_long = cstr; + else + m_cmd_help_long.assign(""); } void @@ -283,7 +276,7 @@ CommandObject::CheckRequirements (CommandReturnObject &result) { Target *target = m_exe_ctx.GetTargetPtr(); if (target) - m_api_locker.Lock (target->GetAPIMutex()); + m_api_locker = std::unique_lock<std::recursive_mutex>(target->GetAPIMutex()); } } @@ -343,46 +336,8 @@ void CommandObject::Cleanup () { m_exe_ctx.Clear(); - m_api_locker.Unlock(); -} - - -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 == nullptr || *m_match_str == '\0') - return true; - - return map_element.first.find (m_match_str, 0) == 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; + if (m_api_locker.owns_lock()) + m_api_locker.unlock(); } int @@ -457,7 +412,11 @@ CommandObject::HandleCompletion } bool -CommandObject::HelpTextContainsWord (const char *search_word) +CommandObject::HelpTextContainsWord (const char *search_word, + bool search_short_help, + bool search_long_help, + bool search_syntax, + bool search_options) { std::string options_usage_help; @@ -467,14 +426,15 @@ CommandObject::HelpTextContainsWord (const char *search_word) const char *long_help = GetHelpLong(); const char *syntax_help = GetSyntax(); - if (short_help && strcasestr (short_help, search_word)) + if (search_short_help && short_help && strcasestr (short_help, search_word)) found_word = true; - else if (long_help && strcasestr (long_help, search_word)) + else if (search_long_help && long_help && strcasestr (long_help, search_word)) found_word = true; - else if (syntax_help && strcasestr (syntax_help, search_word)) + else if (search_syntax && syntax_help && strcasestr (syntax_help, search_word)) found_word = true; if (!found_word + && search_options && GetOptions() != nullptr) { StreamString usage_help; @@ -727,46 +687,47 @@ RegisterNameHelpTextCallback () static const char * BreakpointIDHelpTextCallback () { - return "Breakpoint ID's consist major and minor numbers; the major number " - "corresponds to the single entity that was created with a 'breakpoint set' " - "command; the minor numbers correspond to all the locations that were actually " - "found/set based on the major breakpoint. A full breakpoint ID might look like " - "3.14, meaning the 14th location set for the 3rd breakpoint. You can specify " - "all the locations of a breakpoint by just indicating the major breakpoint " - "number. A valid breakpoint id consists either of just the major id number, " - "or the major number, a dot, and the location number (e.g. 3 or 3.2 could " - "both be valid breakpoint ids)."; + return "Breakpoints are identified using major and minor numbers; the major " + "number corresponds to the single entity that was created with a 'breakpoint " + "set' command; the minor numbers correspond to all the locations that were " + "actually found/set based on the major breakpoint. A full breakpoint ID might " + "look like 3.14, meaning the 14th location set for the 3rd breakpoint. You " + "can specify all the locations of a breakpoint by just indicating the major " + "breakpoint number. A valid breakpoint ID consists either of just the major " + "number, or the major number followed by a dot and the location number (e.g. " + "3 or 3.2 could both be valid breakpoint IDs.)"; } static const char * BreakpointIDRangeHelpTextCallback () { - return "A 'breakpoint id list' is a manner of specifying multiple breakpoints. " - "This can be done through several mechanisms. The easiest way is to just " - "enter a space-separated list of breakpoint ids. To specify all the " - "breakpoint locations under a major breakpoint, you can use the major " - "breakpoint number followed by '.*', eg. '5.*' means all the locations under " - "breakpoint 5. You can also indicate a range of breakpoints by using " - "<start-bp-id> - <end-bp-id>. The start-bp-id and end-bp-id for a range can " - "be any valid breakpoint ids. It is not legal, however, to specify a range " - "using specific locations that cross major breakpoint numbers. I.e. 3.2 - 3.7" - " is legal; 2 - 5 is legal; but 3.2 - 4.4 is not legal."; + return "A 'breakpoint ID list' is a manner of specifying multiple breakpoints. " + "This can be done through several mechanisms. The easiest way is to just " + "enter a space-separated list of breakpoint IDs. To specify all the " + "breakpoint locations under a major breakpoint, you can use the major " + "breakpoint number followed by '.*', eg. '5.*' means all the locations under " + "breakpoint 5. You can also indicate a range of breakpoints by using " + "<start-bp-id> - <end-bp-id>. The start-bp-id and end-bp-id for a range can " + "be any valid breakpoint IDs. It is not legal, however, to specify a range " + "using specific locations that cross major breakpoint numbers. I.e. 3.2 - 3.7" + " is legal; 2 - 5 is legal; but 3.2 - 4.4 is not legal."; } static const char * BreakpointNameHelpTextCallback () { return "A name that can be added to a breakpoint when it is created, or later " - "on with the \"breakpoint name add\" command. " - "Breakpoint names can be used to specify breakpoints in all the places breakpoint ID's " - "and breakpoint ID ranges can be used. As such they provide a convenient way to group breakpoints, " - "and to operate on breakpoints you create without having to track the breakpoint number. " - "Note, the attributes you set when using a breakpoint name in a breakpoint command don't " - "adhere to the name, but instead are set individually on all the breakpoints currently tagged with that name. Future breakpoints " - "tagged with that name will not pick up the attributes previously given using that name. " - "In order to distinguish breakpoint names from breakpoint ID's and ranges, " - "names must start with a letter from a-z or A-Z and cannot contain spaces, \".\" or \"-\". " - "Also, breakpoint names can only be applied to breakpoints, not to breakpoint locations."; + "on with the \"breakpoint name add\" command. " + "Breakpoint names can be used to specify breakpoints in all the places breakpoint IDs " + "and breakpoint ID ranges can be used. As such they provide a convenient way to group breakpoints, " + "and to operate on breakpoints you create without having to track the breakpoint number. " + "Note, the attributes you set when using a breakpoint name in a breakpoint command don't " + "adhere to the name, but instead are set individually on all the breakpoints currently tagged with that " + "name. Future breakpoints " + "tagged with that name will not pick up the attributes previously given using that name. " + "In order to distinguish breakpoint names from breakpoint IDs and ranges, " + "names must start with a letter from a-z or A-Z and cannot contain spaces, \".\" or \"-\". " + "Also, breakpoint names can only be applied to breakpoints, not to breakpoint locations."; } static const char * @@ -956,68 +917,46 @@ void CommandObject::GenerateHelpText (Stream &output_strm) { CommandInterpreter& interpreter = GetCommandInterpreter(); - if (GetOptions() != nullptr) + if (WantsRawCommandString()) + { + std::string help_text(GetHelp()); + help_text.append(" Expects 'raw' input (see 'help raw-input'.)"); + interpreter.OutputFormattedHelpText(output_strm, "", "", help_text.c_str(), 1); + } + else + interpreter.OutputFormattedHelpText(output_strm, "", "", GetHelp(), 1); + output_strm.Printf("\nSyntax: %s\n", GetSyntax()); + Options *options = GetOptions(); + if (options != nullptr) + { + options->GenerateOptionUsage(output_strm, this); + } + const char *long_help = GetHelpLong(); + if ((long_help != nullptr) && (strlen(long_help) > 0)) + { + FormatLongHelpText(output_strm, long_help); + } + if (!IsDashDashCommand() && options && options->NumCommandOptions() > 0) { - if (WantsRawCommandString()) - { - std::string help_text (GetHelp()); - help_text.append (" This command takes 'raw' input (no need to quote stuff)."); - interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1); - } - else - interpreter.OutputFormattedHelpText (output_strm, "", "", GetHelp(), 1); - output_strm.Printf ("\nSyntax: %s\n", GetSyntax()); - GetOptions()->GenerateOptionUsage (output_strm, this); - const char *long_help = GetHelpLong(); - if ((long_help != nullptr) - && (strlen (long_help) > 0)) - FormatLongHelpText (output_strm, long_help); if (WantsRawCommandString() && !WantsCompletion()) { // Emit the message about using ' -- ' between the end of the command options and the raw input // conditionally, i.e., only if the command object does not want completion. - interpreter.OutputFormattedHelpText (output_strm, "", "", - "\nIMPORTANT NOTE: Because this command takes 'raw' input, if you use any command options" - " you must use ' -- ' between the end of the command options and the beginning of the raw input.", 1); + interpreter.OutputFormattedHelpText( + output_strm, "", "", + "\nImportant Note: Because this command takes 'raw' input, if you use any command options" + " you must use ' -- ' between the end of the command options and the beginning of the raw input.", + 1); } - else if (GetNumArgumentEntries() > 0 - && GetOptions() - && GetOptions()->NumCommandOptions() > 0) + else if (GetNumArgumentEntries() > 0) { // Also emit a warning about using "--" in case you are using a command that takes options and arguments. - interpreter.OutputFormattedHelpText (output_strm, "", "", - "\nThis command takes options and free-form arguments. If your arguments resemble" - " option specifiers (i.e., they start with a - or --), you must use ' -- ' between" - " the end of the command options and the beginning of the arguments.", 1); - } - } - else if (IsMultiwordObject()) - { - if (WantsRawCommandString()) - { - std::string help_text (GetHelp()); - help_text.append (" This command takes 'raw' input (no need to quote stuff)."); - interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1); - } - else - interpreter.OutputFormattedHelpText (output_strm, "", "", GetHelp(), 1); - GenerateHelpText (output_strm); - } - else - { - const char *long_help = GetHelpLong(); - if ((long_help != nullptr) - && (strlen (long_help) > 0)) - FormatLongHelpText (output_strm, long_help); - else if (WantsRawCommandString()) - { - std::string help_text (GetHelp()); - help_text.append (" This command takes 'raw' input (no need to quote stuff)."); - interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1); + interpreter.OutputFormattedHelpText( + output_strm, "", "", "\nThis command takes options and free-form arguments. If your arguments resemble" + " option specifiers (i.e., they start with a - or --), you must use ' -- ' between" + " the end of the command options and the beginning of the arguments.", + 1); } - else - interpreter.OutputFormattedHelpText (output_strm, "", "", GetHelp(), 1); - output_strm.Printf ("\nSyntax: %s\n", GetSyntax()); } } @@ -1067,6 +1006,31 @@ CommandObject::GetSelectedOrDummyTarget(bool prefer_dummy) return m_interpreter.GetDebugger().GetSelectedOrDummyTarget(prefer_dummy); } +Thread * +CommandObject::GetDefaultThread() +{ + Thread *thread_to_use = m_exe_ctx.GetThreadPtr(); + if (thread_to_use) + return thread_to_use; + + Process *process = m_exe_ctx.GetProcessPtr(); + if (!process) + { + Target *target = m_exe_ctx.GetTargetPtr(); + if (!target) + { + target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + } + if (target) + process = target->GetProcessSP().get(); + } + + if (process) + return process->GetThreadList().GetSelectedThread().get(); + else + return nullptr; +} + bool CommandObjectParsed::Execute (const char *args_string, CommandReturnObject &result) { @@ -1138,9 +1102,8 @@ const char *arch_helper() return g_archs_help.GetData(); } -CommandObject::ArgumentTableEntry -CommandObject::g_arguments_data[] = -{ +CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = { + // clang-format off { eArgTypeAddress, "address", CommandCompletions::eNoCompletion, { nullptr, false }, "A valid address in the target program's execution space." }, { eArgTypeAddressOrExpression, "address-expression", CommandCompletions::eNoCompletion, { nullptr, false }, "An expression that resolves to an address." }, { eArgTypeAliasName, "alias-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of an abbreviation (alias) for a debugger command." }, @@ -1170,7 +1133,7 @@ CommandObject::g_arguments_data[] = { eArgTypeGDBFormat, "gdb-format", CommandCompletions::eNoCompletion, { GDBFormatHelpTextCallback, true }, nullptr }, { eArgTypeHelpText, "help-text", CommandCompletions::eNoCompletion, { nullptr, false }, "Text to be used as help for some other entity in LLDB" }, { eArgTypeIndex, "index", CommandCompletions::eNoCompletion, { nullptr, false }, "An index into a list." }, - { eArgTypeLanguage, "language", CommandCompletions::eNoCompletion, { LanguageTypeHelpTextCallback, true }, nullptr }, + { eArgTypeLanguage, "source-language", CommandCompletions::eNoCompletion, { LanguageTypeHelpTextCallback, true }, nullptr }, { eArgTypeLineNum, "linenum", CommandCompletions::eNoCompletion, { nullptr, false }, "Line number in a source file." }, { eArgTypeLogCategory, "log-category", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a category within a log channel, e.g. all (try \"log list\" to see a list of all channels and their categories." }, { eArgTypeLogChannel, "log-channel", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a log channel, e.g. process.gdb-remote (try \"log list\" to see a list of all channels and their categories)." }, @@ -1198,7 +1161,7 @@ CommandObject::g_arguments_data[] = { eArgTypeRunMode, "run-mode", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." }, { eArgTypeScriptedCommandSynchronicity, "script-cmd-synchronicity", CommandCompletions::eNoCompletion, { nullptr, false }, "The synchronicity to use to run scripted commands with regard to LLDB event system." }, { eArgTypeScriptLang, "script-language", CommandCompletions::eNoCompletion, { nullptr, false }, "The scripting language to be used for script-based commands. Currently only Python is valid." }, - { eArgTypeSearchWord, "search-word", CommandCompletions::eNoCompletion, { nullptr, false }, "The word for which you wish to search for information about." }, + { eArgTypeSearchWord, "search-word", CommandCompletions::eNoCompletion, { nullptr, false }, "Any word of interest for search purposes." }, { eArgTypeSelector, "selector", CommandCompletions::eNoCompletion, { nullptr, false }, "An Objective-C selector name." }, { eArgTypeSettingIndex, "setting-index", CommandCompletions::eNoCompletion, { nullptr, false }, "An index into a settings variable that is an array (try 'settings list' to see all the possible settings variables and their types)." }, { eArgTypeSettingKey, "setting-key", CommandCompletions::eNoCompletion, { nullptr, false }, "A key into a settings variables that is a dictionary (try 'settings list' to see all the possible settings variables and their types)." }, @@ -1223,7 +1186,9 @@ CommandObject::g_arguments_data[] = { eArgTypePlatform, "platform-name", CommandCompletions::ePlatformPluginCompletion, { nullptr, false }, "The name of an installed platform plug-in . Type 'platform list' to see a complete list of installed platforms." }, { eArgTypeWatchpointID, "watchpt-id", CommandCompletions::eNoCompletion, { nullptr, false }, "Watchpoint IDs are positive integers." }, { eArgTypeWatchpointIDRange, "watchpt-id-list", CommandCompletions::eNoCompletion, { nullptr, false }, "For example, '1-3' or '1 to 3'." }, - { eArgTypeWatchType, "watch-type", CommandCompletions::eNoCompletion, { nullptr, false }, "Specify the type for a watchpoint." } + { eArgTypeWatchType, "watch-type", CommandCompletions::eNoCompletion, { nullptr, false }, "Specify the type for a watchpoint." }, + { eArgRawInput, "raw-input", CommandCompletions::eNoCompletion, { nullptr, false }, "Free-form text passed to a command without prior interpretation, allowing spaces without requiring quotes. To pass arguments and free form text put two dashes ' -- ' between the last argument and any raw input." } + // clang-format on }; const CommandObject::ArgumentTableEntry* diff --git a/source/Interpreter/CommandObjectScript.cpp b/source/Interpreter/CommandObjectScript.cpp index 31e5311ab441..e7de490878fd 100644 --- a/source/Interpreter/CommandObjectScript.cpp +++ b/source/Interpreter/CommandObjectScript.cpp @@ -30,11 +30,10 @@ using namespace lldb_private; // CommandObjectScript //------------------------------------------------------------------------- -CommandObjectScript::CommandObjectScript (CommandInterpreter &interpreter, ScriptLanguage script_lang) : - CommandObjectRaw (interpreter, - "script", - "Pass an expression to the script interpreter for evaluation and return the results. Drop into the interactive interpreter if no expression is given.", - "script [<script-expression-for-evaluation>]") +CommandObjectScript::CommandObjectScript(CommandInterpreter &interpreter, ScriptLanguage script_lang) + : CommandObjectRaw(interpreter, "script", "Invoke the script interpreter with provided code and display any " + "results. Start the interactive interpreter if no code is supplied.", + "script [<script-code>]") { } diff --git a/source/Interpreter/Makefile b/source/Interpreter/Makefile deleted file mode 100644 index 2f25e6796604..000000000000 --- a/source/Interpreter/Makefile +++ /dev/null @@ -1,51 +0,0 @@ -##===- source/Interpreter/Makefile ------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LLDB_LEVEL := ../.. -LIBRARYNAME := lldbInterpreter -BUILD_ARCHIVE = 1 -include $(LLDB_LEVEL)/../../Makefile.config - -ifneq ($(HOST_OS),MingW) -ifeq (,$(findstring -DLLDB_DISABLE_PYTHON,$(CXXFLAGS))) -DO_BUILD_LLDBWrapPython = 1 -BUILT_SOURCES := LLDBWrapPython.cpp -endif -endif - -include $(LLDB_LEVEL)/Makefile --include $(PROJ_OBJ_DIR)/LLDBWrapPython.cpp.d - -ifeq ($(DO_BUILD_LLDBWrapPython),1) -# Drop -Wfour-char-constants, which we are not currently clean with. -EXTRA_OPTIONS += -Wno-four-char-constants - -# Drop -Wself-assign, -Wmissing-field-initializers, -Wsometimes-uninitialized, -# -Wcast-qual, and -Wdeprecated-register which we are not clean with due to SWIG -# generated cpp source. -EXTRA_OPTIONS += -Wno-missing-field-initializers -Wno-self-assign -Wno-sometimes-uninitialized -Wno-cast-qual -Wno-deprecated-register - -PYTHON_DIR := $(PROJ_OBJ_ROOT)/$(BuildMode) - -SWIG_SOURCES := $(shell find $(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts -type f -name '*.swig' -print) - -LLDBWrapPython.cpp lldb.py: $(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/Python/modify-python-lldb.py \ - $(wildcard $(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/interface/*.i) \ - ${SWIG_SOURCES} - $(Echo) Generating LLDBWrapPython.cpp - $(Verb) "$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/prepare_bindings.py" "--src-root=$(PROJ_SRC_DIR)/$(LLDB_LEVEL)" "--target-dir=$(PROJ_OBJ_DIR)" "--config-build-dir=$(PROJ_OBJ_DIR)" "--prefix=$(PYTHON_DIR)" $(if $(DISABLE_AUTO_DEPENDENCIES),,-M) --find-swig - $(Verb) "$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/finish-swig-wrapper-classes.sh" "$(PROJ_SRC_DIR)/$(LLDB_LEVEL)" "$(PROJ_OBJ_DIR)" "$(PROJ_OBJ_DIR)" "$(PYTHON_DIR)" -m - -install-local:: lldb.py - $(Echo) Installing $(BuildMode) LLDB python modules - $(Verb) "$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/scripts/prepare_bindings.py" "--src-root=$(PROJ_SRC_DIR)/$(LLDB_LEVEL)" "--target-dir=$(PROJ_OBJ_DIR)" "--config-build-dir=$(PROJ_OBJ_DIR)" "--prefix=$(DESTDIR)$(prefix)" --find-swig - -clean-local:: - $(Verb) $(RM) -f LLDBWrapPython.cpp lldb.py -endif diff --git a/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/source/Interpreter/OptionGroupValueObjectDisplay.cpp index bbd966859c34..c30a978d9577 100644 --- a/source/Interpreter/OptionGroupValueObjectDisplay.cpp +++ b/source/Interpreter/OptionGroupValueObjectDisplay.cpp @@ -44,7 +44,8 @@ g_option_table[] = { LLDB_OPT_SET_1, false, "no-summary-depth", 'Y', OptionParser::eOptionalArgument, nullptr, nullptr, 0, eArgTypeCount, "Set the depth at which omitting summary information stops (default is 1)."}, { LLDB_OPT_SET_1, false, "raw-output", 'R', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Don't use formatting options."}, { LLDB_OPT_SET_1, false, "show-all-children", 'A', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Ignore the upper bound on the number of children to show."}, - { LLDB_OPT_SET_1, false, "validate", 'V', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Show results of type validators."}, + { LLDB_OPT_SET_1, false, "validate", 'V', OptionParser::eRequiredArgument, nullptr, nullptr,0, eArgTypeBoolean, "Show results of type validators."}, + { LLDB_OPT_SET_1, false, "element-count", 'Z', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "Treat the result of the expression as if its type is an array of this many values."}, { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } }; @@ -92,6 +93,12 @@ OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter, if (!success) error.SetErrorStringWithFormat("invalid max depth '%s'", option_arg); break; + + case 'Z': + elem_count = StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success); + if (!success) + error.SetErrorStringWithFormat("invalid element count '%s'", option_arg); + break; case 'P': ptr_depth = StringConvert::ToUInt32 (option_arg, 0, 0, &success); @@ -141,6 +148,7 @@ OptionGroupValueObjectDisplay::OptionParsingStarting (CommandInterpreter &interp use_objc = false; max_depth = UINT32_MAX; ptr_depth = 0; + elem_count = 0; use_synth = true; be_raw = false; ignore_cap = false; @@ -187,6 +195,8 @@ OptionGroupValueObjectDisplay::GetAsDumpOptions (LanguageRuntimeDescriptionDispl options.SetRawDisplay(); options.SetRunValidator(run_validator); + + options.SetElementCount(elem_count); return options; } diff --git a/source/Interpreter/OptionValueArray.cpp b/source/Interpreter/OptionValueArray.cpp index aabe457534d6..348414f432c9 100644 --- a/source/Interpreter/OptionValueArray.cpp +++ b/source/Interpreter/OptionValueArray.cpp @@ -316,6 +316,7 @@ OptionValueArray::SetArgs (const Args &args, VarSetOperationType op) case eVarSetOperationAssign: m_values.clear(); // Fall through to append case + LLVM_FALLTHROUGH; case eVarSetOperationAppend: for (size_t i=0; i<argc; ++i) { diff --git a/source/Interpreter/OptionValueFileSpecLIst.cpp b/source/Interpreter/OptionValueFileSpecLIst.cpp index 669d3ee33acc..6a0ba11b676c 100644 --- a/source/Interpreter/OptionValueFileSpecLIst.cpp +++ b/source/Interpreter/OptionValueFileSpecLIst.cpp @@ -88,6 +88,7 @@ OptionValueFileSpecList::SetValueFromString (llvm::StringRef value, VarSetOperat case eVarSetOperationAssign: m_current_value.Clear(); // Fall through to append case + LLVM_FALLTHROUGH; case eVarSetOperationAppend: if (argc > 0) { diff --git a/source/Interpreter/OptionValuePathMappings.cpp b/source/Interpreter/OptionValuePathMappings.cpp index 722d6a144279..f3f146f1f8c6 100644 --- a/source/Interpreter/OptionValuePathMappings.cpp +++ b/source/Interpreter/OptionValuePathMappings.cpp @@ -14,11 +14,24 @@ // Other libraries and framework includes // Project includes #include "lldb/Core/Stream.h" +#include "lldb/Host/FileSpec.h" #include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Args.h" using namespace lldb; using namespace lldb_private; +namespace +{ + static bool + VerifyPathExists(const char *path) + { + if (path && path[0]) + return FileSpec(path, false).Exists(); + else + return false; + } +} + void OptionValuePathMappings::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) @@ -59,14 +72,27 @@ OptionValuePathMappings::SetValueFromString (llvm::StringRef value, VarSetOperat } else { + bool changed = false; for (size_t i=1; i<argc; i += 2, ++idx) { - ConstString a(args.GetArgumentAtIndex(i)); - ConstString b(args.GetArgumentAtIndex(i+1)); - if (!m_path_mappings.Replace (a, b, idx, m_notify_changes)) - m_path_mappings.Append(a, b, m_notify_changes); + const char *orginal_path = args.GetArgumentAtIndex(i); + const char *replace_path = args.GetArgumentAtIndex(i+1); + if (VerifyPathExists(replace_path)) + { + ConstString a(orginal_path); + ConstString b(replace_path); + if (!m_path_mappings.Replace (a, b, idx, m_notify_changes)) + m_path_mappings.Append(a, b, m_notify_changes); + changed = true; + } + else + { + error.SetErrorStringWithFormat("the replacement path doesn't exist: \"%s\"", replace_path); + break; + } } - NotifyValueChanged(); + if (changed) + NotifyValueChanged(); } } else @@ -85,6 +111,7 @@ OptionValuePathMappings::SetValueFromString (llvm::StringRef value, VarSetOperat } m_path_mappings.Clear(m_notify_changes); // Fall through to append case + LLVM_FALLTHROUGH; case eVarSetOperationAppend: if (argc < 2 || (argc & 1)) { @@ -93,14 +120,27 @@ OptionValuePathMappings::SetValueFromString (llvm::StringRef value, VarSetOperat } else { + bool changed = false; for (size_t i=0; i<argc; i += 2) { - ConstString a(args.GetArgumentAtIndex(i)); - ConstString b(args.GetArgumentAtIndex(i+1)); - m_path_mappings.Append(a, b, m_notify_changes); - m_value_was_set = true; + const char *orginal_path = args.GetArgumentAtIndex(i); + const char *replace_path = args.GetArgumentAtIndex(i+1); + if (VerifyPathExists(replace_path)) + { + ConstString a(orginal_path); + ConstString b(replace_path); + m_path_mappings.Append(a, b, m_notify_changes); + m_value_was_set = true; + changed = true; + } + else + { + error.SetErrorStringWithFormat("the replacement path doesn't exist: \"%s\"", replace_path); + break; + } } - NotifyValueChanged(); + if (changed) + NotifyValueChanged(); } break; @@ -117,15 +157,28 @@ OptionValuePathMappings::SetValueFromString (llvm::StringRef value, VarSetOperat } else { + bool changed = false; if (op == eVarSetOperationInsertAfter) ++idx; for (size_t i=1; i<argc; i += 2, ++idx) { - ConstString a(args.GetArgumentAtIndex(i)); - ConstString b(args.GetArgumentAtIndex(i+1)); - m_path_mappings.Insert (a, b, idx, m_notify_changes); + const char *orginal_path = args.GetArgumentAtIndex(i); + const char *replace_path = args.GetArgumentAtIndex(i+1); + if (VerifyPathExists(replace_path)) + { + ConstString a(orginal_path); + ConstString b(replace_path); + m_path_mappings.Insert (a, b, idx, m_notify_changes); + changed = true; + } + else + { + error.SetErrorStringWithFormat("the replacement path doesn't exist: \"%s\"", replace_path); + break; + } } - NotifyValueChanged(); + if (changed) + NotifyValueChanged(); } } else diff --git a/source/Interpreter/OptionValueProperties.cpp b/source/Interpreter/OptionValueProperties.cpp index a3c28f70270f..7024c3601d9f 100644 --- a/source/Interpreter/OptionValueProperties.cpp +++ b/source/Interpreter/OptionValueProperties.cpp @@ -164,8 +164,23 @@ OptionValueProperties::GetSubValue (const ExecutionContext *exe_ctx, switch (sub_name[0]) { case '.': - return value_sp->GetSubValue (exe_ctx, sub_name + 1, will_modify, error); - + { + lldb::OptionValueSP return_val_sp; + return_val_sp = value_sp->GetSubValue (exe_ctx, sub_name + 1, will_modify, error); + if (!return_val_sp) + { + if (Properties::IsSettingExperimental(sub_name + 1)) + { + size_t experimental_len = strlen(Properties::GetExperimentalSettingsName()); + if (*(sub_name + experimental_len + 1) == '.') + return_val_sp = value_sp->GetSubValue(exe_ctx, sub_name + experimental_len + 2, will_modify, error); + // It isn't an error if an experimental setting is not present. + if (!return_val_sp) + error.Clear(); + } + } + return return_val_sp; + } case '{': // Predicate matching for predicates like // "<setting-name>{<predicate>}" diff --git a/source/Interpreter/Options.cpp b/source/Interpreter/Options.cpp index 7f0e0abc03ea..70f532ed75de 100644 --- a/source/Interpreter/Options.cpp +++ b/source/Interpreter/Options.cpp @@ -14,6 +14,7 @@ #include <algorithm> #include <bitset> #include <map> +#include <set> // Other libraries and framework includes // Project includes @@ -477,6 +478,7 @@ Options::GenerateOptionUsage CommandObject *cmd ) { + const bool only_print_args = cmd->IsDashDashCommand(); const uint32_t screen_width = m_interpreter.GetDebugger().GetTerminalWidth(); const OptionDefinition *opt_defs = GetDefinitions(); @@ -509,203 +511,211 @@ Options::GenerateOptionUsage uint32_t i; - for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set) + if (!only_print_args) { - uint32_t opt_set_mask; - - opt_set_mask = 1 << opt_set; - if (opt_set > 0) - strm.Printf ("\n"); - strm.Indent (name); - - // Different option sets may require different args. - StreamString args_str; - if (cmd) - cmd->GetFormattedCommandArguments(args_str, opt_set_mask); - - // First go through and print all options that take no arguments as - // a single string. If a command has "-a" "-b" and "-c", this will show - // up as [-abc] - - std::set<int> options; - std::set<int>::const_iterator options_pos, options_end; - for (i = 0; i < num_options; ++i) + for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set) { - if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option)) + uint32_t opt_set_mask; + + opt_set_mask = 1 << opt_set; + if (opt_set > 0) + strm.Printf ("\n"); + strm.Indent (name); + + // Different option sets may require different args. + StreamString args_str; + if (cmd) + cmd->GetFormattedCommandArguments(args_str, opt_set_mask); + + // First go through and print all options that take no arguments as + // a single string. If a command has "-a" "-b" and "-c", this will show + // up as [-abc] + + std::set<int> options; + std::set<int>::const_iterator options_pos, options_end; + for (i = 0; i < num_options; ++i) { - // Add current option to the end of out_stream. - - if (opt_defs[i].required == true && - opt_defs[i].option_has_arg == OptionParser::eNoArgument) + if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option)) { - options.insert (opt_defs[i].short_option); - } - } - } + // Add current option to the end of out_stream. - if (options.empty() == false) - { - // We have some required options with no arguments - strm.PutCString(" -"); - for (i=0; i<2; ++i) - for (options_pos = options.begin(), options_end = options.end(); - options_pos != options_end; - ++options_pos) - { - if (i==0 && ::islower (*options_pos)) - continue; - if (i==1 && ::isupper (*options_pos)) - continue; - strm << (char)*options_pos; + if (opt_defs[i].required == true && + opt_defs[i].option_has_arg == OptionParser::eNoArgument) + { + options.insert (opt_defs[i].short_option); + } } - } + } - for (i = 0, options.clear(); i < num_options; ++i) - { - if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option)) + if (options.empty() == false) { - // Add current option to the end of out_stream. + // We have some required options with no arguments + strm.PutCString(" -"); + for (i=0; i<2; ++i) + for (options_pos = options.begin(), options_end = options.end(); + options_pos != options_end; + ++options_pos) + { + if (i==0 && ::islower (*options_pos)) + continue; + if (i==1 && ::isupper (*options_pos)) + continue; + strm << (char)*options_pos; + } + } - if (opt_defs[i].required == false && - opt_defs[i].option_has_arg == OptionParser::eNoArgument) + for (i = 0, options.clear(); i < num_options; ++i) + { + if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option)) { - options.insert (opt_defs[i].short_option); + // Add current option to the end of out_stream. + + if (opt_defs[i].required == false && + opt_defs[i].option_has_arg == OptionParser::eNoArgument) + { + options.insert (opt_defs[i].short_option); + } } } - } - if (options.empty() == false) - { - // We have some required options with no arguments - strm.PutCString(" [-"); - for (i=0; i<2; ++i) - for (options_pos = options.begin(), options_end = options.end(); - options_pos != options_end; - ++options_pos) - { - if (i==0 && ::islower (*options_pos)) - continue; - if (i==1 && ::isupper (*options_pos)) - continue; - strm << (char)*options_pos; - } - strm.PutChar(']'); - } + if (options.empty() == false) + { + // We have some required options with no arguments + strm.PutCString(" [-"); + for (i=0; i<2; ++i) + for (options_pos = options.begin(), options_end = options.end(); + options_pos != options_end; + ++options_pos) + { + if (i==0 && ::islower (*options_pos)) + continue; + if (i==1 && ::isupper (*options_pos)) + continue; + strm << (char)*options_pos; + } + strm.PutChar(']'); + } - // First go through and print the required options (list them up front). - - for (i = 0; i < num_options; ++i) - { - if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option)) + // First go through and print the required options (list them up front). + + for (i = 0; i < num_options; ++i) { - if (opt_defs[i].required && opt_defs[i].option_has_arg != OptionParser::eNoArgument) - PrintOption (opt_defs[i], eDisplayBestOption, " ", nullptr, true, strm); + if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option)) + { + if (opt_defs[i].required && opt_defs[i].option_has_arg != OptionParser::eNoArgument) + PrintOption (opt_defs[i], eDisplayBestOption, " ", nullptr, true, strm); + } } - } - // Now go through again, and this time only print the optional options. + // Now go through again, and this time only print the optional options. - for (i = 0; i < num_options; ++i) - { - if (opt_defs[i].usage_mask & opt_set_mask) + for (i = 0; i < num_options; ++i) { - // Add current option to the end of out_stream. + if (opt_defs[i].usage_mask & opt_set_mask) + { + // Add current option to the end of out_stream. - if (!opt_defs[i].required && opt_defs[i].option_has_arg != OptionParser::eNoArgument) - PrintOption (opt_defs[i], eDisplayBestOption, " ", nullptr, true, strm); + if (!opt_defs[i].required && opt_defs[i].option_has_arg != OptionParser::eNoArgument) + PrintOption (opt_defs[i], eDisplayBestOption, " ", nullptr, true, strm); + } } - } - - if (args_str.GetSize() > 0) - { - if (cmd->WantsRawCommandString()) - strm.Printf(" --"); - strm.Printf (" %s", args_str.GetData()); + if (args_str.GetSize() > 0) + { + if (cmd->WantsRawCommandString() && !only_print_args) + strm.Printf(" --"); + + strm.Printf (" %s", args_str.GetData()); + if (only_print_args) + break; + } } } if (cmd && - cmd->WantsRawCommandString() && + (only_print_args || cmd->WantsRawCommandString()) && arguments_str.GetSize() > 0) { - strm.PutChar('\n'); + if (!only_print_args) strm.PutChar('\n'); strm.Indent(name); strm.Printf(" %s", arguments_str.GetData()); } strm.Printf ("\n\n"); - // Now print out all the detailed information about the various options: long form, short form and help text: - // -short <argument> ( --long_name <argument> ) - // help text + if (!only_print_args) + { + // Now print out all the detailed information about the various options: long form, short form and help text: + // -short <argument> ( --long_name <argument> ) + // help text - // This variable is used to keep track of which options' info we've printed out, because some options can be in - // more than one usage level, but we only want to print the long form of its information once. + // This variable is used to keep track of which options' info we've printed out, because some options can be in + // more than one usage level, but we only want to print the long form of its information once. - std::multimap<int, uint32_t> options_seen; - strm.IndentMore (5); + std::multimap<int, uint32_t> options_seen; + strm.IndentMore (5); - // Put the unique command options in a vector & sort it, so we can output them alphabetically (by short_option) - // when writing out detailed help for each option. + // Put the unique command options in a vector & sort it, so we can output them alphabetically (by short_option) + // when writing out detailed help for each option. - for (i = 0; i < num_options; ++i) - options_seen.insert(std::make_pair(opt_defs[i].short_option, i)); + for (i = 0; i < num_options; ++i) + options_seen.insert(std::make_pair(opt_defs[i].short_option, i)); - // Go through the unique'd and alphabetically sorted vector of options, find the table entry for each option - // and write out the detailed help information for that option. + // Go through the unique'd and alphabetically sorted vector of options, find the table entry for each option + // and write out the detailed help information for that option. - bool first_option_printed = false;; + bool first_option_printed = false;; - for (auto pos : options_seen) - { - i = pos.second; - //Print out the help information for this option. + for (auto pos : options_seen) + { + i = pos.second; + //Print out the help information for this option. - // Put a newline separation between arguments - if (first_option_printed) - strm.EOL(); - else - first_option_printed = true; - - CommandArgumentType arg_type = opt_defs[i].argument_type; - - StreamString arg_name_str; - arg_name_str.Printf ("<%s>", CommandObject::GetArgumentName (arg_type)); + // Put a newline separation between arguments + if (first_option_printed) + strm.EOL(); + else + first_option_printed = true; + + CommandArgumentType arg_type = opt_defs[i].argument_type; + + StreamString arg_name_str; + arg_name_str.Printf ("<%s>", CommandObject::GetArgumentName (arg_type)); - strm.Indent (); - if (opt_defs[i].short_option && isprint8(opt_defs[i].short_option)) - { - PrintOption (opt_defs[i], eDisplayShortOption, nullptr, nullptr, false, strm); - PrintOption (opt_defs[i], eDisplayLongOption, " ( ", " )", false, strm); - } - else - { - // Short option is not printable, just print long option - PrintOption (opt_defs[i], eDisplayLongOption, nullptr, nullptr, false, strm); - } - strm.EOL(); - - strm.IndentMore (5); - - if (opt_defs[i].usage_text) - OutputFormattedUsageText (strm, - opt_defs[i], - screen_width); - if (opt_defs[i].enum_values != nullptr) - { strm.Indent (); - strm.Printf("Values: "); - for (int k = 0; opt_defs[i].enum_values[k].string_value != nullptr; k++) + if (opt_defs[i].short_option && isprint8(opt_defs[i].short_option)) { - if (k == 0) - strm.Printf("%s", opt_defs[i].enum_values[k].string_value); - else - strm.Printf(" | %s", opt_defs[i].enum_values[k].string_value); + PrintOption (opt_defs[i], eDisplayShortOption, nullptr, nullptr, false, strm); + PrintOption (opt_defs[i], eDisplayLongOption, " ( ", " )", false, strm); + } + else + { + // Short option is not printable, just print long option + PrintOption (opt_defs[i], eDisplayLongOption, nullptr, nullptr, false, strm); } strm.EOL(); + + strm.IndentMore (5); + + if (opt_defs[i].usage_text) + OutputFormattedUsageText (strm, + opt_defs[i], + screen_width); + if (opt_defs[i].enum_values != nullptr) + { + strm.Indent (); + strm.Printf("Values: "); + for (int k = 0; opt_defs[i].enum_values[k].string_value != nullptr; k++) + { + if (k == 0) + strm.Printf("%s", opt_defs[i].enum_values[k].string_value); + else + strm.Printf(" | %s", opt_defs[i].enum_values[k].string_value); + } + strm.EOL(); + } + strm.IndentLess (5); } - strm.IndentLess (5); } // Restore the indent level @@ -954,6 +964,13 @@ Options::HandleOptionArgumentCompletion for (size_t i = 0; i < opt_element_vector.size(); i++) { int cur_defs_index = opt_element_vector[i].opt_defs_index; + + // trying to use <0 indices will definitely cause problems + if (cur_defs_index == OptionArgElement::eUnrecognizedArg || + cur_defs_index == OptionArgElement::eBareDash || + cur_defs_index == OptionArgElement::eBareDoubleDash) + continue; + int cur_arg_pos = opt_element_vector[i].opt_arg_pos; const char *cur_opt_name = opt_defs[cur_defs_index].long_option; |