1 //===-- CommandObjectMultiword.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 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 // Project includes 14 #include "lldb/Interpreter/CommandObjectMultiword.h" 15 #include "lldb/Core/Debugger.h" 16 #include "lldb/Interpreter/CommandInterpreter.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 //------------------------------------------------------------------------- 24 // CommandObjectMultiword 25 //------------------------------------------------------------------------- 26 27 CommandObjectMultiword::CommandObjectMultiword(CommandInterpreter &interpreter, 28 const char *name, 29 const char *help, 30 const char *syntax, 31 uint32_t flags) 32 : CommandObject(interpreter, name, help, syntax, flags), 33 m_can_be_removed(false) {} 34 35 CommandObjectMultiword::~CommandObjectMultiword() = default; 36 37 CommandObjectSP CommandObjectMultiword::GetSubcommandSP(llvm::StringRef sub_cmd, 38 StringList *matches) { 39 CommandObjectSP return_cmd_sp; 40 CommandObject::CommandMap::iterator pos; 41 42 if (!m_subcommand_dict.empty()) { 43 pos = m_subcommand_dict.find(sub_cmd); 44 if (pos != m_subcommand_dict.end()) { 45 // An exact match; append the sub_cmd to the 'matches' string list. 46 if (matches) 47 matches->AppendString(sub_cmd); 48 return_cmd_sp = pos->second; 49 } else { 50 StringList local_matches; 51 if (matches == nullptr) 52 matches = &local_matches; 53 int num_matches = 54 AddNamesMatchingPartialString(m_subcommand_dict, sub_cmd, *matches); 55 56 if (num_matches == 1) { 57 // Cleaner, but slightly less efficient would be to call back into this 58 // function, since I now know I have an exact match... 59 60 sub_cmd = matches->GetStringAtIndex(0); 61 pos = m_subcommand_dict.find(sub_cmd); 62 if (pos != m_subcommand_dict.end()) 63 return_cmd_sp = pos->second; 64 } 65 } 66 } 67 return return_cmd_sp; 68 } 69 70 CommandObject * 71 CommandObjectMultiword::GetSubcommandObject(llvm::StringRef sub_cmd, 72 StringList *matches) { 73 return GetSubcommandSP(sub_cmd, matches).get(); 74 } 75 76 bool CommandObjectMultiword::LoadSubCommand(llvm::StringRef name, 77 const CommandObjectSP &cmd_obj) { 78 if (cmd_obj) 79 assert((&GetCommandInterpreter() == &cmd_obj->GetCommandInterpreter()) && 80 "tried to add a CommandObject from a different interpreter"); 81 82 CommandMap::iterator pos; 83 bool success = true; 84 85 pos = m_subcommand_dict.find(name); 86 if (pos == m_subcommand_dict.end()) { 87 m_subcommand_dict[name] = cmd_obj; 88 } else 89 success = false; 90 91 return success; 92 } 93 94 bool CommandObjectMultiword::Execute(const char *args_string, 95 CommandReturnObject &result) { 96 Args args(args_string); 97 const size_t argc = args.GetArgumentCount(); 98 if (argc == 0) { 99 this->CommandObject::GenerateHelpText(result); 100 return result.Succeeded(); 101 } 102 103 auto sub_command = args[0].ref; 104 if (sub_command.empty()) 105 return result.Succeeded(); 106 107 if (sub_command.equals_lower("help")) { 108 this->CommandObject::GenerateHelpText(result); 109 return result.Succeeded(); 110 } 111 112 if (m_subcommand_dict.empty()) { 113 result.AppendErrorWithFormat("'%s' does not have any subcommands.\n", 114 GetCommandName().str().c_str()); 115 result.SetStatus(eReturnStatusFailed); 116 return false; 117 } 118 119 StringList matches; 120 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches); 121 if (sub_cmd_obj != nullptr) { 122 // Now call CommandObject::Execute to process options in `rest_of_line`. 123 // From there the command-specific version of Execute will be called, with 124 // the processed arguments. 125 126 args.Shift(); 127 sub_cmd_obj->Execute(args_string, result); 128 return result.Succeeded(); 129 } 130 131 std::string error_msg; 132 const size_t num_subcmd_matches = matches.GetSize(); 133 if (num_subcmd_matches > 0) 134 error_msg.assign("ambiguous command "); 135 else 136 error_msg.assign("invalid command "); 137 138 error_msg.append("'"); 139 error_msg.append(GetCommandName()); 140 error_msg.append(" "); 141 error_msg.append(sub_command); 142 error_msg.append("'."); 143 144 if (num_subcmd_matches > 0) { 145 error_msg.append(" Possible completions:"); 146 for (size_t i = 0; i < num_subcmd_matches; i++) { 147 error_msg.append("\n\t"); 148 error_msg.append(matches.GetStringAtIndex(i)); 149 } 150 } 151 error_msg.append("\n"); 152 result.AppendRawError(error_msg.c_str()); 153 result.SetStatus(eReturnStatusFailed); 154 return false; 155 } 156 157 void CommandObjectMultiword::GenerateHelpText(Stream &output_stream) { 158 // First time through here, generate the help text for the object and push it 159 // to the return result object as well 160 161 CommandObject::GenerateHelpText(output_stream); 162 output_stream.PutCString("\nThe following subcommands are supported:\n\n"); 163 164 CommandMap::iterator pos; 165 uint32_t max_len = FindLongestCommandWord(m_subcommand_dict); 166 167 if (max_len) 168 max_len += 4; // Indent the output by 4 spaces. 169 170 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) { 171 std::string indented_command(" "); 172 indented_command.append(pos->first); 173 if (pos->second->WantsRawCommandString()) { 174 std::string help_text(pos->second->GetHelp()); 175 help_text.append(" Expects 'raw' input (see 'help raw-input'.)"); 176 m_interpreter.OutputFormattedHelpText(output_stream, 177 indented_command.c_str(), "--", 178 help_text.c_str(), max_len); 179 } else 180 m_interpreter.OutputFormattedHelpText(output_stream, 181 indented_command.c_str(), "--", 182 pos->second->GetHelp(), max_len); 183 } 184 185 output_stream.PutCString("\nFor more help on any particular subcommand, type " 186 "'help <command> <subcommand>'.\n"); 187 } 188 189 int CommandObjectMultiword::HandleCompletion(Args &input, int &cursor_index, 190 int &cursor_char_position, 191 int match_start_point, 192 int max_return_elements, 193 bool &word_complete, 194 StringList &matches) { 195 // Any of the command matches will provide a complete word, otherwise the 196 // individual completers will override this. 197 word_complete = true; 198 199 auto arg0 = input[0].ref; 200 if (cursor_index == 0) { 201 AddNamesMatchingPartialString(m_subcommand_dict, arg0, matches); 202 203 if (matches.GetSize() == 1 && matches.GetStringAtIndex(0) != nullptr && 204 (arg0 == matches.GetStringAtIndex(0))) { 205 StringList temp_matches; 206 CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches); 207 if (cmd_obj != nullptr) { 208 if (input.GetArgumentCount() == 1) { 209 word_complete = true; 210 } else { 211 matches.DeleteStringAtIndex(0); 212 input.Shift(); 213 cursor_char_position = 0; 214 input.AppendArgument(llvm::StringRef()); 215 return cmd_obj->HandleCompletion( 216 input, cursor_index, cursor_char_position, match_start_point, 217 max_return_elements, word_complete, matches); 218 } 219 } 220 } 221 return matches.GetSize(); 222 } else { 223 CommandObject *sub_command_object = GetSubcommandObject(arg0, &matches); 224 if (sub_command_object == nullptr) { 225 return matches.GetSize(); 226 } else { 227 // Remove the one match that we got from calling GetSubcommandObject. 228 matches.DeleteStringAtIndex(0); 229 input.Shift(); 230 cursor_index--; 231 return sub_command_object->HandleCompletion( 232 input, cursor_index, cursor_char_position, match_start_point, 233 max_return_elements, word_complete, matches); 234 } 235 } 236 } 237 238 const char *CommandObjectMultiword::GetRepeatCommand(Args ¤t_command_args, 239 uint32_t index) { 240 index++; 241 if (current_command_args.GetArgumentCount() <= index) 242 return nullptr; 243 CommandObject *sub_command_object = 244 GetSubcommandObject(current_command_args[index].ref); 245 if (sub_command_object == nullptr) 246 return nullptr; 247 return sub_command_object->GetRepeatCommand(current_command_args, index); 248 } 249 250 void CommandObjectMultiword::AproposAllSubCommands(llvm::StringRef prefix, 251 llvm::StringRef search_word, 252 StringList &commands_found, 253 StringList &commands_help) { 254 CommandObject::CommandMap::const_iterator pos; 255 256 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) { 257 const char *command_name = pos->first.c_str(); 258 CommandObject *sub_cmd_obj = pos->second.get(); 259 StreamString complete_command_name; 260 261 complete_command_name << prefix << " " << command_name; 262 263 if (sub_cmd_obj->HelpTextContainsWord(search_word)) { 264 commands_found.AppendString(complete_command_name.GetString()); 265 commands_help.AppendString(sub_cmd_obj->GetHelp()); 266 } 267 268 if (sub_cmd_obj->IsMultiwordObject()) 269 sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(), 270 search_word, commands_found, 271 commands_help); 272 } 273 } 274 275 CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter, 276 const char *name, const char *help, 277 const char *syntax, uint32_t flags) 278 : CommandObject(interpreter, name, help, syntax, flags) {} 279 280 CommandObjectProxy::~CommandObjectProxy() = default; 281 282 llvm::StringRef CommandObjectProxy::GetHelpLong() { 283 CommandObject *proxy_command = GetProxyCommandObject(); 284 if (proxy_command) 285 return proxy_command->GetHelpLong(); 286 return llvm::StringRef(); 287 } 288 289 bool CommandObjectProxy::IsRemovable() const { 290 const CommandObject *proxy_command = 291 const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject(); 292 if (proxy_command) 293 return proxy_command->IsRemovable(); 294 return false; 295 } 296 297 bool CommandObjectProxy::IsMultiwordObject() { 298 CommandObject *proxy_command = GetProxyCommandObject(); 299 if (proxy_command) 300 return proxy_command->IsMultiwordObject(); 301 return false; 302 } 303 304 CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() { 305 CommandObject *proxy_command = GetProxyCommandObject(); 306 if (proxy_command) 307 return proxy_command->GetAsMultiwordCommand(); 308 return nullptr; 309 } 310 311 void CommandObjectProxy::GenerateHelpText(Stream &result) { 312 CommandObject *proxy_command = GetProxyCommandObject(); 313 if (proxy_command) 314 return proxy_command->GenerateHelpText(result); 315 } 316 317 lldb::CommandObjectSP 318 CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd, 319 StringList *matches) { 320 CommandObject *proxy_command = GetProxyCommandObject(); 321 if (proxy_command) 322 return proxy_command->GetSubcommandSP(sub_cmd, matches); 323 return lldb::CommandObjectSP(); 324 } 325 326 CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd, 327 StringList *matches) { 328 CommandObject *proxy_command = GetProxyCommandObject(); 329 if (proxy_command) 330 return proxy_command->GetSubcommandObject(sub_cmd, matches); 331 return nullptr; 332 } 333 334 void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix, 335 llvm::StringRef search_word, 336 StringList &commands_found, 337 StringList &commands_help) { 338 CommandObject *proxy_command = GetProxyCommandObject(); 339 if (proxy_command) 340 return proxy_command->AproposAllSubCommands(prefix, search_word, 341 commands_found, commands_help); 342 } 343 344 bool CommandObjectProxy::LoadSubCommand( 345 llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) { 346 CommandObject *proxy_command = GetProxyCommandObject(); 347 if (proxy_command) 348 return proxy_command->LoadSubCommand(cmd_name, command_sp); 349 return false; 350 } 351 352 bool CommandObjectProxy::WantsRawCommandString() { 353 CommandObject *proxy_command = GetProxyCommandObject(); 354 if (proxy_command) 355 return proxy_command->WantsRawCommandString(); 356 return false; 357 } 358 359 bool CommandObjectProxy::WantsCompletion() { 360 CommandObject *proxy_command = GetProxyCommandObject(); 361 if (proxy_command) 362 return proxy_command->WantsCompletion(); 363 return false; 364 } 365 366 Options *CommandObjectProxy::GetOptions() { 367 CommandObject *proxy_command = GetProxyCommandObject(); 368 if (proxy_command) 369 return proxy_command->GetOptions(); 370 return nullptr; 371 } 372 373 int CommandObjectProxy::HandleCompletion(Args &input, int &cursor_index, 374 int &cursor_char_position, 375 int match_start_point, 376 int max_return_elements, 377 bool &word_complete, 378 StringList &matches) { 379 CommandObject *proxy_command = GetProxyCommandObject(); 380 if (proxy_command) 381 return proxy_command->HandleCompletion( 382 input, cursor_index, cursor_char_position, match_start_point, 383 max_return_elements, word_complete, matches); 384 matches.Clear(); 385 return 0; 386 } 387 388 int CommandObjectProxy::HandleArgumentCompletion( 389 Args &input, int &cursor_index, int &cursor_char_position, 390 OptionElementVector &opt_element_vector, int match_start_point, 391 int max_return_elements, bool &word_complete, StringList &matches) { 392 CommandObject *proxy_command = GetProxyCommandObject(); 393 if (proxy_command) 394 return proxy_command->HandleArgumentCompletion( 395 input, cursor_index, cursor_char_position, opt_element_vector, 396 match_start_point, max_return_elements, word_complete, matches); 397 matches.Clear(); 398 return 0; 399 } 400 401 const char *CommandObjectProxy::GetRepeatCommand(Args ¤t_command_args, 402 uint32_t index) { 403 CommandObject *proxy_command = GetProxyCommandObject(); 404 if (proxy_command) 405 return proxy_command->GetRepeatCommand(current_command_args, index); 406 return nullptr; 407 } 408 409 bool CommandObjectProxy::Execute(const char *args_string, 410 CommandReturnObject &result) { 411 CommandObject *proxy_command = GetProxyCommandObject(); 412 if (proxy_command) 413 return proxy_command->Execute(args_string, result); 414 result.AppendError("command is not implemented"); 415 result.SetStatus(eReturnStatusFailed); 416 return false; 417 } 418