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