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 output_stream.PutCString ("The following subcommands are supported:\n\n"); 182 183 CommandMap::iterator pos; 184 uint32_t max_len = FindLongestCommandWord (m_subcommand_dict); 185 186 if (max_len) 187 max_len += 4; // Indent the output by 4 spaces. 188 189 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) 190 { 191 std::string indented_command (" "); 192 indented_command.append (pos->first); 193 if (pos->second->WantsRawCommandString ()) 194 { 195 std::string help_text (pos->second->GetHelp()); 196 help_text.append (" This command takes 'raw' input (no need to quote stuff)."); 197 m_interpreter.OutputFormattedHelpText (output_stream, 198 indented_command.c_str(), 199 "--", 200 help_text.c_str(), 201 max_len); 202 } 203 else 204 m_interpreter.OutputFormattedHelpText (output_stream, 205 indented_command.c_str(), 206 "--", 207 pos->second->GetHelp(), 208 max_len); 209 } 210 211 output_stream.PutCString ("\nFor more help on any particular subcommand, type 'help <command> <subcommand>'.\n"); 212 } 213 214 int 215 CommandObjectMultiword::HandleCompletion(Args &input, 216 int &cursor_index, 217 int &cursor_char_position, 218 int match_start_point, 219 int max_return_elements, 220 bool &word_complete, 221 StringList &matches) 222 { 223 // Any of the command matches will provide a complete word, otherwise the individual 224 // completers will override this. 225 word_complete = true; 226 227 const char *arg0 = input.GetArgumentAtIndex(0); 228 if (cursor_index == 0) 229 { 230 AddNamesMatchingPartialString (m_subcommand_dict, 231 arg0, 232 matches); 233 234 if (matches.GetSize() == 1 235 && matches.GetStringAtIndex(0) != nullptr 236 && strcmp (arg0, matches.GetStringAtIndex(0)) == 0) 237 { 238 StringList temp_matches; 239 CommandObject *cmd_obj = GetSubcommandObject (arg0, 240 &temp_matches); 241 if (cmd_obj != nullptr) 242 { 243 if (input.GetArgumentCount() == 1) 244 { 245 word_complete = true; 246 } 247 else 248 { 249 matches.DeleteStringAtIndex (0); 250 input.Shift(); 251 cursor_char_position = 0; 252 input.AppendArgument (""); 253 return cmd_obj->HandleCompletion (input, 254 cursor_index, 255 cursor_char_position, 256 match_start_point, 257 max_return_elements, 258 word_complete, 259 matches); 260 } 261 } 262 } 263 return matches.GetSize(); 264 } 265 else 266 { 267 CommandObject *sub_command_object = GetSubcommandObject (arg0, 268 &matches); 269 if (sub_command_object == nullptr) 270 { 271 return matches.GetSize(); 272 } 273 else 274 { 275 // Remove the one match that we got from calling GetSubcommandObject. 276 matches.DeleteStringAtIndex(0); 277 input.Shift(); 278 cursor_index--; 279 return sub_command_object->HandleCompletion (input, 280 cursor_index, 281 cursor_char_position, 282 match_start_point, 283 max_return_elements, 284 word_complete, 285 matches); 286 } 287 } 288 } 289 290 const char * 291 CommandObjectMultiword::GetRepeatCommand (Args ¤t_command_args, uint32_t index) 292 { 293 index++; 294 if (current_command_args.GetArgumentCount() <= index) 295 return nullptr; 296 CommandObject *sub_command_object = GetSubcommandObject (current_command_args.GetArgumentAtIndex(index)); 297 if (sub_command_object == nullptr) 298 return nullptr; 299 return sub_command_object->GetRepeatCommand(current_command_args, index); 300 } 301 302 void 303 CommandObjectMultiword::AproposAllSubCommands (const char *prefix, 304 const char *search_word, 305 StringList &commands_found, 306 StringList &commands_help) 307 { 308 CommandObject::CommandMap::const_iterator pos; 309 310 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) 311 { 312 const char * command_name = pos->first.c_str(); 313 CommandObject *sub_cmd_obj = pos->second.get(); 314 StreamString complete_command_name; 315 316 complete_command_name.Printf ("%s %s", prefix, command_name); 317 318 if (sub_cmd_obj->HelpTextContainsWord (search_word)) 319 { 320 commands_found.AppendString (complete_command_name.GetData()); 321 commands_help.AppendString (sub_cmd_obj->GetHelp()); 322 } 323 324 if (sub_cmd_obj->IsMultiwordObject()) 325 sub_cmd_obj->AproposAllSubCommands (complete_command_name.GetData(), 326 search_word, 327 commands_found, 328 commands_help); 329 } 330 } 331 332 CommandObjectProxy::CommandObjectProxy (CommandInterpreter &interpreter, 333 const char *name, 334 const char *help, 335 const char *syntax, 336 uint32_t flags) : 337 CommandObject (interpreter, name, help, syntax, flags) 338 { 339 } 340 341 CommandObjectProxy::~CommandObjectProxy() = default; 342 343 const char * 344 CommandObjectProxy::GetHelpLong () 345 { 346 CommandObject *proxy_command = GetProxyCommandObject(); 347 if (proxy_command) 348 return proxy_command->GetHelpLong(); 349 return nullptr; 350 } 351 352 bool 353 CommandObjectProxy::IsRemovable() const 354 { 355 const CommandObject *proxy_command = const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject(); 356 if (proxy_command) 357 return proxy_command->IsRemovable(); 358 return false; 359 } 360 361 bool 362 CommandObjectProxy::IsMultiwordObject () 363 { 364 CommandObject *proxy_command = GetProxyCommandObject(); 365 if (proxy_command) 366 return proxy_command->IsMultiwordObject(); 367 return false; 368 } 369 370 CommandObjectMultiword* 371 CommandObjectProxy::GetAsMultiwordCommand () 372 { 373 CommandObject *proxy_command = GetProxyCommandObject(); 374 if (proxy_command) 375 return proxy_command->GetAsMultiwordCommand(); 376 return nullptr; 377 } 378 379 void 380 CommandObjectProxy::GenerateHelpText (Stream &result) 381 { 382 CommandObject *proxy_command = GetProxyCommandObject(); 383 if (proxy_command) 384 return proxy_command->GenerateHelpText(result); 385 } 386 387 lldb::CommandObjectSP 388 CommandObjectProxy::GetSubcommandSP (const char *sub_cmd, StringList *matches) 389 { 390 CommandObject *proxy_command = GetProxyCommandObject(); 391 if (proxy_command) 392 return proxy_command->GetSubcommandSP(sub_cmd, matches); 393 return lldb::CommandObjectSP(); 394 } 395 396 CommandObject * 397 CommandObjectProxy::GetSubcommandObject (const char *sub_cmd, StringList *matches) 398 { 399 CommandObject *proxy_command = GetProxyCommandObject(); 400 if (proxy_command) 401 return proxy_command->GetSubcommandObject(sub_cmd, matches); 402 return nullptr; 403 } 404 405 void 406 CommandObjectProxy::AproposAllSubCommands (const char *prefix, 407 const char *search_word, 408 StringList &commands_found, 409 StringList &commands_help) 410 { 411 CommandObject *proxy_command = GetProxyCommandObject(); 412 if (proxy_command) 413 return proxy_command->AproposAllSubCommands (prefix, 414 search_word, 415 commands_found, 416 commands_help); 417 } 418 419 bool 420 CommandObjectProxy::LoadSubCommand (const char *cmd_name, 421 const lldb::CommandObjectSP& command_sp) 422 { 423 CommandObject *proxy_command = GetProxyCommandObject(); 424 if (proxy_command) 425 return proxy_command->LoadSubCommand (cmd_name, command_sp); 426 return false; 427 } 428 429 bool 430 CommandObjectProxy::WantsRawCommandString() 431 { 432 CommandObject *proxy_command = GetProxyCommandObject(); 433 if (proxy_command) 434 return proxy_command->WantsRawCommandString(); 435 return false; 436 } 437 438 bool 439 CommandObjectProxy::WantsCompletion() 440 { 441 CommandObject *proxy_command = GetProxyCommandObject(); 442 if (proxy_command) 443 return proxy_command->WantsCompletion(); 444 return false; 445 } 446 447 Options * 448 CommandObjectProxy::GetOptions () 449 { 450 CommandObject *proxy_command = GetProxyCommandObject(); 451 if (proxy_command) 452 return proxy_command->GetOptions (); 453 return nullptr; 454 } 455 456 int 457 CommandObjectProxy::HandleCompletion (Args &input, 458 int &cursor_index, 459 int &cursor_char_position, 460 int match_start_point, 461 int max_return_elements, 462 bool &word_complete, 463 StringList &matches) 464 { 465 CommandObject *proxy_command = GetProxyCommandObject(); 466 if (proxy_command) 467 return proxy_command->HandleCompletion (input, 468 cursor_index, 469 cursor_char_position, 470 match_start_point, 471 max_return_elements, 472 word_complete, 473 matches); 474 matches.Clear(); 475 return 0; 476 } 477 478 int 479 CommandObjectProxy::HandleArgumentCompletion (Args &input, 480 int &cursor_index, 481 int &cursor_char_position, 482 OptionElementVector &opt_element_vector, 483 int match_start_point, 484 int max_return_elements, 485 bool &word_complete, 486 StringList &matches) 487 { 488 CommandObject *proxy_command = GetProxyCommandObject(); 489 if (proxy_command) 490 return proxy_command->HandleArgumentCompletion (input, 491 cursor_index, 492 cursor_char_position, 493 opt_element_vector, 494 match_start_point, 495 max_return_elements, 496 word_complete, 497 matches); 498 matches.Clear(); 499 return 0; 500 } 501 502 const char * 503 CommandObjectProxy::GetRepeatCommand (Args ¤t_command_args, 504 uint32_t index) 505 { 506 CommandObject *proxy_command = GetProxyCommandObject(); 507 if (proxy_command) 508 return proxy_command->GetRepeatCommand (current_command_args, index); 509 return nullptr; 510 } 511 512 bool 513 CommandObjectProxy::Execute (const char *args_string, 514 CommandReturnObject &result) 515 { 516 CommandObject *proxy_command = GetProxyCommandObject(); 517 if (proxy_command) 518 return proxy_command->Execute (args_string, result); 519 result.AppendError ("command is not implemented"); 520 result.SetStatus (eReturnStatusFailed); 521 return false; 522 } 523