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