1 //===-- CommandAlias.cpp -----------------------------------------*- C++-*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Interpreter/CommandAlias.h" 11 12 #include "llvm/Support/ErrorHandling.h" 13 14 #include "lldb/Interpreter/CommandInterpreter.h" 15 #include "lldb/Interpreter/CommandObject.h" 16 #include "lldb/Interpreter/CommandReturnObject.h" 17 #include "lldb/Interpreter/Options.h" 18 #include "lldb/Utility/StreamString.h" 19 20 using namespace lldb; 21 using namespace lldb_private; 22 23 static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP &cmd_obj_sp, 24 llvm::StringRef options_args, 25 OptionArgVectorSP &option_arg_vector_sp) { 26 bool success = true; 27 OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); 28 29 if (options_args.size() < 1) 30 return true; 31 32 Args args(options_args); 33 std::string options_string(options_args); 34 CommandReturnObject result; 35 // Check to see if the command being aliased can take any command options. 36 Options *options = cmd_obj_sp->GetOptions(); 37 if (options) { 38 // See if any options were specified as part of the alias; if so, handle 39 // them appropriately. 40 ExecutionContext exe_ctx = 41 cmd_obj_sp->GetCommandInterpreter().GetExecutionContext(); 42 options->NotifyOptionParsingStarting(&exe_ctx); 43 44 llvm::Expected<Args> args_or = 45 options->ParseAlias(args, option_arg_vector, options_string); 46 if (!args_or) { 47 result.AppendError(toString(args_or.takeError())); 48 result.AppendError("Unable to create requested alias.\n"); 49 result.SetStatus(eReturnStatusFailed); 50 return false; 51 } 52 args = std::move(*args_or); 53 options->VerifyPartialOptions(result); 54 if (!result.Succeeded() && 55 result.GetStatus() != lldb::eReturnStatusStarted) { 56 result.AppendError("Unable to create requested alias.\n"); 57 return false; 58 } 59 } 60 61 if (!options_string.empty()) { 62 if (cmd_obj_sp->WantsRawCommandString()) 63 option_arg_vector->emplace_back("<argument>", -1, options_string); 64 else { 65 for (auto &entry : args.entries()) { 66 if (!entry.ref.empty()) 67 option_arg_vector->emplace_back("<argument>", -1, entry.ref); 68 } 69 } 70 } 71 72 return success; 73 } 74 75 CommandAlias::CommandAlias(CommandInterpreter &interpreter, 76 lldb::CommandObjectSP cmd_sp, 77 llvm::StringRef options_args, llvm::StringRef name, 78 llvm::StringRef help, llvm::StringRef syntax, 79 uint32_t flags) 80 : CommandObject(interpreter, name, help, syntax, flags), 81 m_underlying_command_sp(), m_option_string(options_args), 82 m_option_args_sp(new OptionArgVector), 83 m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false), 84 m_did_set_help_long(false) { 85 if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) { 86 m_underlying_command_sp = cmd_sp; 87 for (int i = 0; 88 auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i); 89 i++) { 90 m_arguments.push_back(*cmd_entry); 91 } 92 if (!help.empty()) { 93 StreamString sstr; 94 StreamString translation_and_help; 95 GetAliasExpansion(sstr); 96 97 translation_and_help.Printf( 98 "(%s) %s", sstr.GetData(), 99 GetUnderlyingCommand()->GetHelp().str().c_str()); 100 SetHelp(translation_and_help.GetString()); 101 } 102 } 103 } 104 105 bool CommandAlias::WantsRawCommandString() { 106 if (IsValid()) 107 return m_underlying_command_sp->WantsRawCommandString(); 108 return false; 109 } 110 111 bool CommandAlias::WantsCompletion() { 112 if (IsValid()) 113 return m_underlying_command_sp->WantsCompletion(); 114 return false; 115 } 116 117 int CommandAlias::HandleCompletion(Args &input, int &cursor_index, 118 int &cursor_char_position, 119 int match_start_point, 120 int max_return_elements, bool &word_complete, 121 StringList &matches) { 122 if (IsValid()) 123 return m_underlying_command_sp->HandleCompletion( 124 input, cursor_index, cursor_char_position, match_start_point, 125 max_return_elements, word_complete, matches); 126 return -1; 127 } 128 129 int CommandAlias::HandleArgumentCompletion( 130 Args &input, int &cursor_index, int &cursor_char_position, 131 OptionElementVector &opt_element_vector, int match_start_point, 132 int max_return_elements, bool &word_complete, StringList &matches) { 133 if (IsValid()) 134 return m_underlying_command_sp->HandleArgumentCompletion( 135 input, cursor_index, cursor_char_position, opt_element_vector, 136 match_start_point, max_return_elements, word_complete, matches); 137 return -1; 138 } 139 140 Options *CommandAlias::GetOptions() { 141 if (IsValid()) 142 return m_underlying_command_sp->GetOptions(); 143 return nullptr; 144 } 145 146 bool CommandAlias::Execute(const char *args_string, 147 CommandReturnObject &result) { 148 llvm_unreachable("CommandAlias::Execute is not to be called"); 149 } 150 151 void CommandAlias::GetAliasExpansion(StreamString &help_string) const { 152 llvm::StringRef command_name = m_underlying_command_sp->GetCommandName(); 153 help_string.Printf("'%*s", (int)command_name.size(), command_name.data()); 154 155 if (!m_option_args_sp) { 156 help_string.Printf("'"); 157 return; 158 } 159 160 OptionArgVector *options = m_option_args_sp.get(); 161 std::string opt; 162 std::string value; 163 164 for (const auto &opt_entry : *options) { 165 std::tie(opt, std::ignore, value) = opt_entry; 166 if (opt == "<argument>") { 167 help_string.Printf(" %s", value.c_str()); 168 } else { 169 help_string.Printf(" %s", opt.c_str()); 170 if ((value.compare("<no-argument>") != 0) && 171 (value.compare("<need-argument") != 0)) { 172 help_string.Printf(" %s", value.c_str()); 173 } 174 } 175 } 176 177 help_string.Printf("'"); 178 } 179 180 bool CommandAlias::IsDashDashCommand() { 181 if (m_is_dashdash_alias != eLazyBoolCalculate) 182 return (m_is_dashdash_alias == eLazyBoolYes); 183 m_is_dashdash_alias = eLazyBoolNo; 184 if (!IsValid()) 185 return false; 186 187 std::string opt; 188 std::string value; 189 190 for (const auto &opt_entry : *GetOptionArguments()) { 191 std::tie(opt, std::ignore, value) = opt_entry; 192 if (opt == "<argument>" && !value.empty() && 193 llvm::StringRef(value).endswith("--")) { 194 m_is_dashdash_alias = eLazyBoolYes; 195 break; 196 } 197 } 198 199 // if this is a nested alias, it may be adding arguments on top of an 200 // already dash-dash alias 201 if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias()) 202 m_is_dashdash_alias = 203 (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes 204 : eLazyBoolNo); 205 return (m_is_dashdash_alias == eLazyBoolYes); 206 } 207 208 bool CommandAlias::IsNestedAlias() { 209 if (GetUnderlyingCommand()) 210 return GetUnderlyingCommand()->IsAlias(); 211 return false; 212 } 213 214 std::pair<lldb::CommandObjectSP, OptionArgVectorSP> CommandAlias::Desugar() { 215 auto underlying = GetUnderlyingCommand(); 216 if (!underlying) 217 return {nullptr, nullptr}; 218 219 if (underlying->IsAlias()) { 220 auto desugared = ((CommandAlias *)underlying.get())->Desugar(); 221 auto options = GetOptionArguments(); 222 options->insert(options->begin(), desugared.second->begin(), 223 desugared.second->end()); 224 return {desugared.first, options}; 225 } 226 227 return {underlying, GetOptionArguments()}; 228 } 229 230 // allow CommandAlias objects to provide their own help, but fallback to the 231 // info 232 // for the underlying command if no customization has been provided 233 void CommandAlias::SetHelp(llvm::StringRef str) { 234 this->CommandObject::SetHelp(str); 235 m_did_set_help = true; 236 } 237 238 void CommandAlias::SetHelpLong(llvm::StringRef str) { 239 this->CommandObject::SetHelpLong(str); 240 m_did_set_help_long = true; 241 } 242 243 llvm::StringRef CommandAlias::GetHelp() { 244 if (!m_cmd_help_short.empty() || m_did_set_help) 245 return m_cmd_help_short; 246 if (IsValid()) 247 return m_underlying_command_sp->GetHelp(); 248 return llvm::StringRef(); 249 } 250 251 llvm::StringRef CommandAlias::GetHelpLong() { 252 if (!m_cmd_help_long.empty() || m_did_set_help_long) 253 return m_cmd_help_long; 254 if (IsValid()) 255 return m_underlying_command_sp->GetHelpLong(); 256 return llvm::StringRef(); 257 } 258