253 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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/Interpreter/CommandInterpreter.h"
 | |
| #include "lldb/Interpreter/CommandObject.h"
 | |
| #include "lldb/Interpreter/CommandReturnObject.h"
 | |
| #include "lldb/Interpreter/Options.h"
 | |
| #include "lldb/Utility/StreamString.h"
 | |
| 
 | |
| using namespace lldb;
 | |
| using namespace lldb_private;
 | |
| 
 | |
| static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP &cmd_obj_sp,
 | |
|                                     llvm::StringRef options_args,
 | |
|                                     OptionArgVectorSP &option_arg_vector_sp) {
 | |
|   bool success = true;
 | |
|   OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
 | |
| 
 | |
|   if (options_args.size() < 1)
 | |
|     return true;
 | |
| 
 | |
|   Args args(options_args);
 | |
|   std::string options_string(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.
 | |
|     ExecutionContext exe_ctx =
 | |
|         cmd_obj_sp->GetCommandInterpreter().GetExecutionContext();
 | |
|     options->NotifyOptionParsingStarting(&exe_ctx);
 | |
|     args.Unshift(llvm::StringRef("dummy_arg"));
 | |
|     options_string = args.ParseAliasOptions(*options, result, option_arg_vector,
 | |
|                                             options_args);
 | |
|     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->emplace_back("<argument>", -1, options_string);
 | |
|     else {
 | |
|       for (auto &entry : args.entries()) {
 | |
|         if (!entry.ref.empty())
 | |
|           option_arg_vector->emplace_back("<argument>", -1, entry.ref);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return success;
 | |
| }
 | |
| 
 | |
| CommandAlias::CommandAlias(CommandInterpreter &interpreter,
 | |
|                            lldb::CommandObjectSP cmd_sp,
 | |
|                            llvm::StringRef options_args, llvm::StringRef name,
 | |
|                            llvm::StringRef help, llvm::StringRef syntax,
 | |
|                            uint32_t flags)
 | |
|     : CommandObject(interpreter, name, help, syntax, flags),
 | |
|       m_underlying_command_sp(), m_option_string(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.empty()) {
 | |
|       StreamString sstr;
 | |
|       StreamString translation_and_help;
 | |
|       GetAliasExpansion(sstr);
 | |
| 
 | |
|       translation_and_help.Printf(
 | |
|           "(%s)  %s", sstr.GetData(),
 | |
|           GetUnderlyingCommand()->GetHelp().str().c_str());
 | |
|       SetHelp(translation_and_help.GetString());
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| 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 {
 | |
|   llvm::StringRef command_name = m_underlying_command_sp->GetCommandName();
 | |
|   help_string.Printf("'%*s", (int)command_name.size(), command_name.data());
 | |
| 
 | |
|   if (!m_option_args_sp) {
 | |
|     help_string.Printf("'");
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   OptionArgVector *options = m_option_args_sp.get();
 | |
|   std::string opt;
 | |
|   std::string value;
 | |
| 
 | |
|   for (const auto &opt_entry : *options) {
 | |
|     std::tie(opt, std::ignore, value) = opt_entry;
 | |
|     if (opt == "<argument>") {
 | |
|       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)
 | |
|     return (m_is_dashdash_alias == eLazyBoolYes);
 | |
|   m_is_dashdash_alias = eLazyBoolNo;
 | |
|   if (!IsValid())
 | |
|     return false;
 | |
| 
 | |
|   std::string opt;
 | |
|   std::string value;
 | |
| 
 | |
|   for (const auto &opt_entry : *GetOptionArguments()) {
 | |
|     std::tie(opt, std::ignore, value) = opt_entry;
 | |
|     if (opt == "<argument>" && !value.empty() &&
 | |
|         llvm::StringRef(value).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(llvm::StringRef str) {
 | |
|   this->CommandObject::SetHelp(str);
 | |
|   m_did_set_help = true;
 | |
| }
 | |
| 
 | |
| void CommandAlias::SetHelpLong(llvm::StringRef str) {
 | |
|   this->CommandObject::SetHelpLong(str);
 | |
|   m_did_set_help_long = true;
 | |
| }
 | |
| 
 | |
| llvm::StringRef CommandAlias::GetHelp() {
 | |
|   if (!m_cmd_help_short.empty() || m_did_set_help)
 | |
|     return m_cmd_help_short;
 | |
|   if (IsValid())
 | |
|     return m_underlying_command_sp->GetHelp();
 | |
|   return llvm::StringRef();
 | |
| }
 | |
| 
 | |
| llvm::StringRef CommandAlias::GetHelpLong() {
 | |
|   if (!m_cmd_help_long.empty() || m_did_set_help_long)
 | |
|     return m_cmd_help_long;
 | |
|   if (IsValid())
 | |
|     return m_underlying_command_sp->GetHelpLong();
 | |
|   return llvm::StringRef();
 | |
| }
 |