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