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