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/Core/StreamString.h" 15 #include "lldb/Interpreter/CommandInterpreter.h" 16 #include "lldb/Interpreter/CommandObject.h" 17 #include "lldb/Interpreter/CommandReturnObject.h" 18 #include "lldb/Interpreter/Options.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 args.Unshift(llvm::StringRef("dummy_arg")); 44 options_string = args.ParseAliasOptions(*options, result, option_arg_vector, 45 options_args); 46 args.Shift(); 47 if (result.Succeeded()) 48 options->VerifyPartialOptions(result); 49 if (!result.Succeeded() && 50 result.GetStatus() != lldb::eReturnStatusStarted) { 51 result.AppendError("Unable to create requested alias.\n"); 52 return false; 53 } 54 } 55 56 if (!options_string.empty()) { 57 if (cmd_obj_sp->WantsRawCommandString()) 58 option_arg_vector->emplace_back("<argument>", -1, options_string); 59 else { 60 for (auto &entry : args.entries()) { 61 if (!entry.ref.empty()) 62 option_arg_vector->emplace_back("<argument>", -1, entry.ref); 63 } 64 } 65 } 66 67 return success; 68 } 69 70 CommandAlias::CommandAlias(CommandInterpreter &interpreter, 71 lldb::CommandObjectSP cmd_sp, 72 llvm::StringRef options_args, llvm::StringRef name, 73 llvm::StringRef help, llvm::StringRef syntax, 74 uint32_t flags) 75 : CommandObject(interpreter, name, help, syntax, flags), 76 m_underlying_command_sp(), m_option_string(options_args), 77 m_option_args_sp(new OptionArgVector), 78 m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false), 79 m_did_set_help_long(false) { 80 if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp)) { 81 m_underlying_command_sp = cmd_sp; 82 for (int i = 0; 83 auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i); 84 i++) { 85 m_arguments.push_back(*cmd_entry); 86 } 87 if (!help.empty()) { 88 StreamString sstr; 89 StreamString translation_and_help; 90 GetAliasExpansion(sstr); 91 92 translation_and_help.Printf("(%s) %s", sstr.GetData(), 93 GetUnderlyingCommand()->GetHelp()); 94 SetHelp(translation_and_help.GetData()); 95 } 96 } 97 } 98 99 bool CommandAlias::WantsRawCommandString() { 100 if (IsValid()) 101 return m_underlying_command_sp->WantsRawCommandString(); 102 return false; 103 } 104 105 bool CommandAlias::WantsCompletion() { 106 if (IsValid()) 107 return m_underlying_command_sp->WantsCompletion(); 108 return false; 109 } 110 111 int CommandAlias::HandleCompletion(Args &input, int &cursor_index, 112 int &cursor_char_position, 113 int match_start_point, 114 int max_return_elements, bool &word_complete, 115 StringList &matches) { 116 if (IsValid()) 117 return m_underlying_command_sp->HandleCompletion( 118 input, cursor_index, cursor_char_position, match_start_point, 119 max_return_elements, word_complete, matches); 120 return -1; 121 } 122 123 int CommandAlias::HandleArgumentCompletion( 124 Args &input, int &cursor_index, int &cursor_char_position, 125 OptionElementVector &opt_element_vector, int match_start_point, 126 int max_return_elements, bool &word_complete, StringList &matches) { 127 if (IsValid()) 128 return m_underlying_command_sp->HandleArgumentCompletion( 129 input, cursor_index, cursor_char_position, opt_element_vector, 130 match_start_point, max_return_elements, word_complete, matches); 131 return -1; 132 } 133 134 Options *CommandAlias::GetOptions() { 135 if (IsValid()) 136 return m_underlying_command_sp->GetOptions(); 137 return nullptr; 138 } 139 140 bool CommandAlias::Execute(const char *args_string, 141 CommandReturnObject &result) { 142 llvm_unreachable("CommandAlias::Execute is not to be called"); 143 } 144 145 void CommandAlias::GetAliasExpansion(StreamString &help_string) const { 146 llvm::StringRef command_name = m_underlying_command_sp->GetCommandName(); 147 help_string.Printf("'%*s", (int)command_name.size(), command_name.data()); 148 149 if (!m_option_args_sp) { 150 help_string.Printf("'"); 151 return; 152 } 153 154 OptionArgVector *options = m_option_args_sp.get(); 155 std::string opt; 156 std::string value; 157 158 for (const auto &opt_entry : *options) { 159 std::tie(opt, std::ignore, value) = opt_entry; 160 if (opt == "<argument>") { 161 help_string.Printf(" %s", value.c_str()); 162 } else { 163 help_string.Printf(" %s", opt.c_str()); 164 if ((value.compare("<no-argument>") != 0) && 165 (value.compare("<need-argument") != 0)) { 166 help_string.Printf(" %s", value.c_str()); 167 } 168 } 169 } 170 171 help_string.Printf("'"); 172 } 173 174 bool CommandAlias::IsDashDashCommand() { 175 if (m_is_dashdash_alias != eLazyBoolCalculate) 176 return (m_is_dashdash_alias == eLazyBoolYes); 177 m_is_dashdash_alias = eLazyBoolNo; 178 if (!IsValid()) 179 return false; 180 181 std::string opt; 182 std::string value; 183 184 for (const auto &opt_entry : *GetOptionArguments()) { 185 std::tie(opt, std::ignore, value) = opt_entry; 186 if (opt == "<argument>" && !value.empty() && 187 llvm::StringRef(value).endswith("--")) { 188 m_is_dashdash_alias = eLazyBoolYes; 189 break; 190 } 191 } 192 193 // if this is a nested alias, it may be adding arguments on top of an 194 // already dash-dash alias 195 if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias()) 196 m_is_dashdash_alias = 197 (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes 198 : eLazyBoolNo); 199 return (m_is_dashdash_alias == eLazyBoolYes); 200 } 201 202 bool CommandAlias::IsNestedAlias() { 203 if (GetUnderlyingCommand()) 204 return GetUnderlyingCommand()->IsAlias(); 205 return false; 206 } 207 208 std::pair<lldb::CommandObjectSP, OptionArgVectorSP> CommandAlias::Desugar() { 209 auto underlying = GetUnderlyingCommand(); 210 if (!underlying) 211 return {nullptr, nullptr}; 212 213 if (underlying->IsAlias()) { 214 auto desugared = ((CommandAlias *)underlying.get())->Desugar(); 215 auto options = GetOptionArguments(); 216 options->insert(options->begin(), desugared.second->begin(), 217 desugared.second->end()); 218 return {desugared.first, options}; 219 } 220 221 return {underlying, GetOptionArguments()}; 222 } 223 224 // allow CommandAlias objects to provide their own help, but fallback to the 225 // info 226 // for the underlying command if no customization has been provided 227 void CommandAlias::SetHelp(const char *str) { 228 this->CommandObject::SetHelp(str); 229 m_did_set_help = true; 230 } 231 232 void CommandAlias::SetHelpLong(const char *str) { 233 this->CommandObject::SetHelpLong(str); 234 m_did_set_help_long = true; 235 } 236 237 const char *CommandAlias::GetHelp() { 238 if (!m_cmd_help_short.empty() || m_did_set_help) 239 return m_cmd_help_short.c_str(); 240 if (IsValid()) 241 return m_underlying_command_sp->GetHelp(); 242 return nullptr; 243 } 244 245 const char *CommandAlias::GetHelpLong() { 246 if (!m_cmd_help_long.empty() || m_did_set_help_long) 247 return m_cmd_help_long.c_str(); 248 if (IsValid()) 249 return m_underlying_command_sp->GetHelpLong(); 250 return nullptr; 251 } 252