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 void 371 CommandObjectProxy::GenerateHelpText (Stream &result) 372 { 373 CommandObject *proxy_command = GetProxyCommandObject(); 374 if (proxy_command) 375 return proxy_command->GenerateHelpText(result); 376 } 377 378 lldb::CommandObjectSP 379 CommandObjectProxy::GetSubcommandSP (const char *sub_cmd, StringList *matches) 380 { 381 CommandObject *proxy_command = GetProxyCommandObject(); 382 if (proxy_command) 383 return proxy_command->GetSubcommandSP(sub_cmd, matches); 384 return lldb::CommandObjectSP(); 385 } 386 387 CommandObject * 388 CommandObjectProxy::GetSubcommandObject (const char *sub_cmd, StringList *matches) 389 { 390 CommandObject *proxy_command = GetProxyCommandObject(); 391 if (proxy_command) 392 return proxy_command->GetSubcommandObject(sub_cmd, matches); 393 return nullptr; 394 } 395 396 void 397 CommandObjectProxy::AproposAllSubCommands (const char *prefix, 398 const char *search_word, 399 StringList &commands_found, 400 StringList &commands_help) 401 { 402 CommandObject *proxy_command = GetProxyCommandObject(); 403 if (proxy_command) 404 return proxy_command->AproposAllSubCommands (prefix, 405 search_word, 406 commands_found, 407 commands_help); 408 } 409 410 bool 411 CommandObjectProxy::LoadSubCommand (const char *cmd_name, 412 const lldb::CommandObjectSP& command_sp) 413 { 414 CommandObject *proxy_command = GetProxyCommandObject(); 415 if (proxy_command) 416 return proxy_command->LoadSubCommand (cmd_name, command_sp); 417 return false; 418 } 419 420 bool 421 CommandObjectProxy::WantsRawCommandString() 422 { 423 CommandObject *proxy_command = GetProxyCommandObject(); 424 if (proxy_command) 425 return proxy_command->WantsRawCommandString(); 426 return false; 427 } 428 429 bool 430 CommandObjectProxy::WantsCompletion() 431 { 432 CommandObject *proxy_command = GetProxyCommandObject(); 433 if (proxy_command) 434 return proxy_command->WantsCompletion(); 435 return false; 436 } 437 438 Options * 439 CommandObjectProxy::GetOptions () 440 { 441 CommandObject *proxy_command = GetProxyCommandObject(); 442 if (proxy_command) 443 return proxy_command->GetOptions (); 444 return nullptr; 445 } 446 447 int 448 CommandObjectProxy::HandleCompletion (Args &input, 449 int &cursor_index, 450 int &cursor_char_position, 451 int match_start_point, 452 int max_return_elements, 453 bool &word_complete, 454 StringList &matches) 455 { 456 CommandObject *proxy_command = GetProxyCommandObject(); 457 if (proxy_command) 458 return proxy_command->HandleCompletion (input, 459 cursor_index, 460 cursor_char_position, 461 match_start_point, 462 max_return_elements, 463 word_complete, 464 matches); 465 matches.Clear(); 466 return 0; 467 } 468 469 int 470 CommandObjectProxy::HandleArgumentCompletion (Args &input, 471 int &cursor_index, 472 int &cursor_char_position, 473 OptionElementVector &opt_element_vector, 474 int match_start_point, 475 int max_return_elements, 476 bool &word_complete, 477 StringList &matches) 478 { 479 CommandObject *proxy_command = GetProxyCommandObject(); 480 if (proxy_command) 481 return proxy_command->HandleArgumentCompletion (input, 482 cursor_index, 483 cursor_char_position, 484 opt_element_vector, 485 match_start_point, 486 max_return_elements, 487 word_complete, 488 matches); 489 matches.Clear(); 490 return 0; 491 } 492 493 const char * 494 CommandObjectProxy::GetRepeatCommand (Args ¤t_command_args, 495 uint32_t index) 496 { 497 CommandObject *proxy_command = GetProxyCommandObject(); 498 if (proxy_command) 499 return proxy_command->GetRepeatCommand (current_command_args, index); 500 return nullptr; 501 } 502 503 bool 504 CommandObjectProxy::Execute (const char *args_string, 505 CommandReturnObject &result) 506 { 507 CommandObject *proxy_command = GetProxyCommandObject(); 508 if (proxy_command) 509 return proxy_command->Execute (args_string, result); 510 result.AppendError ("command is not implemented"); 511 result.SetStatus (eReturnStatusFailed); 512 return false; 513 } 514