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