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