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(Args &input, int &cursor_index,
190                                              int &cursor_char_position,
191                                              int match_start_point,
192                                              int max_return_elements,
193                                              bool &word_complete,
194                                              StringList &matches) {
195   // Any of the command matches will provide a complete word, otherwise the
196   // individual completers will override this.
197   word_complete = true;
198 
199   auto arg0 = input[0].ref;
200   if (cursor_index == 0) {
201     AddNamesMatchingPartialString(m_subcommand_dict, arg0, matches);
202 
203     if (matches.GetSize() == 1 && matches.GetStringAtIndex(0) != nullptr &&
204         (arg0 == matches.GetStringAtIndex(0))) {
205       StringList temp_matches;
206       CommandObject *cmd_obj = GetSubcommandObject(arg0, &temp_matches);
207       if (cmd_obj != nullptr) {
208         if (input.GetArgumentCount() == 1) {
209           word_complete = true;
210         } else {
211           matches.DeleteStringAtIndex(0);
212           input.Shift();
213           cursor_char_position = 0;
214           input.AppendArgument(llvm::StringRef());
215           return cmd_obj->HandleCompletion(
216               input, cursor_index, cursor_char_position, match_start_point,
217               max_return_elements, word_complete, matches);
218         }
219       }
220     }
221     return matches.GetSize();
222   } else {
223     CommandObject *sub_command_object = GetSubcommandObject(arg0, &matches);
224     if (sub_command_object == nullptr) {
225       return matches.GetSize();
226     } else {
227       // Remove the one match that we got from calling GetSubcommandObject.
228       matches.DeleteStringAtIndex(0);
229       input.Shift();
230       cursor_index--;
231       return sub_command_object->HandleCompletion(
232           input, cursor_index, cursor_char_position, match_start_point,
233           max_return_elements, word_complete, matches);
234     }
235   }
236 }
237 
238 const char *CommandObjectMultiword::GetRepeatCommand(Args &current_command_args,
239                                                      uint32_t index) {
240   index++;
241   if (current_command_args.GetArgumentCount() <= index)
242     return nullptr;
243   CommandObject *sub_command_object =
244       GetSubcommandObject(current_command_args[index].ref);
245   if (sub_command_object == nullptr)
246     return nullptr;
247   return sub_command_object->GetRepeatCommand(current_command_args, index);
248 }
249 
250 void CommandObjectMultiword::AproposAllSubCommands(llvm::StringRef prefix,
251                                                    llvm::StringRef search_word,
252                                                    StringList &commands_found,
253                                                    StringList &commands_help) {
254   CommandObject::CommandMap::const_iterator pos;
255 
256   for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos) {
257     const char *command_name = pos->first.c_str();
258     CommandObject *sub_cmd_obj = pos->second.get();
259     StreamString complete_command_name;
260 
261     complete_command_name << prefix << " " << command_name;
262 
263     if (sub_cmd_obj->HelpTextContainsWord(search_word)) {
264       commands_found.AppendString(complete_command_name.GetString());
265       commands_help.AppendString(sub_cmd_obj->GetHelp());
266     }
267 
268     if (sub_cmd_obj->IsMultiwordObject())
269       sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(),
270                                          search_word, commands_found,
271                                          commands_help);
272   }
273 }
274 
275 CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter,
276                                        const char *name, const char *help,
277                                        const char *syntax, uint32_t flags)
278     : CommandObject(interpreter, name, help, syntax, flags) {}
279 
280 CommandObjectProxy::~CommandObjectProxy() = default;
281 
282 llvm::StringRef CommandObjectProxy::GetHelpLong() {
283   CommandObject *proxy_command = GetProxyCommandObject();
284   if (proxy_command)
285     return proxy_command->GetHelpLong();
286   return llvm::StringRef();
287 }
288 
289 bool CommandObjectProxy::IsRemovable() const {
290   const CommandObject *proxy_command =
291       const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
292   if (proxy_command)
293     return proxy_command->IsRemovable();
294   return false;
295 }
296 
297 bool CommandObjectProxy::IsMultiwordObject() {
298   CommandObject *proxy_command = GetProxyCommandObject();
299   if (proxy_command)
300     return proxy_command->IsMultiwordObject();
301   return false;
302 }
303 
304 CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() {
305   CommandObject *proxy_command = GetProxyCommandObject();
306   if (proxy_command)
307     return proxy_command->GetAsMultiwordCommand();
308   return nullptr;
309 }
310 
311 void CommandObjectProxy::GenerateHelpText(Stream &result) {
312   CommandObject *proxy_command = GetProxyCommandObject();
313   if (proxy_command)
314     return proxy_command->GenerateHelpText(result);
315 }
316 
317 lldb::CommandObjectSP
318 CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd,
319                                     StringList *matches) {
320   CommandObject *proxy_command = GetProxyCommandObject();
321   if (proxy_command)
322     return proxy_command->GetSubcommandSP(sub_cmd, matches);
323   return lldb::CommandObjectSP();
324 }
325 
326 CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd,
327                                                        StringList *matches) {
328   CommandObject *proxy_command = GetProxyCommandObject();
329   if (proxy_command)
330     return proxy_command->GetSubcommandObject(sub_cmd, matches);
331   return nullptr;
332 }
333 
334 void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix,
335                                                llvm::StringRef search_word,
336                                                StringList &commands_found,
337                                                StringList &commands_help) {
338   CommandObject *proxy_command = GetProxyCommandObject();
339   if (proxy_command)
340     return proxy_command->AproposAllSubCommands(prefix, search_word,
341                                                 commands_found, commands_help);
342 }
343 
344 bool CommandObjectProxy::LoadSubCommand(
345     llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
346   CommandObject *proxy_command = GetProxyCommandObject();
347   if (proxy_command)
348     return proxy_command->LoadSubCommand(cmd_name, command_sp);
349   return false;
350 }
351 
352 bool CommandObjectProxy::WantsRawCommandString() {
353   CommandObject *proxy_command = GetProxyCommandObject();
354   if (proxy_command)
355     return proxy_command->WantsRawCommandString();
356   return false;
357 }
358 
359 bool CommandObjectProxy::WantsCompletion() {
360   CommandObject *proxy_command = GetProxyCommandObject();
361   if (proxy_command)
362     return proxy_command->WantsCompletion();
363   return false;
364 }
365 
366 Options *CommandObjectProxy::GetOptions() {
367   CommandObject *proxy_command = GetProxyCommandObject();
368   if (proxy_command)
369     return proxy_command->GetOptions();
370   return nullptr;
371 }
372 
373 int CommandObjectProxy::HandleCompletion(Args &input, int &cursor_index,
374                                          int &cursor_char_position,
375                                          int match_start_point,
376                                          int max_return_elements,
377                                          bool &word_complete,
378                                          StringList &matches) {
379   CommandObject *proxy_command = GetProxyCommandObject();
380   if (proxy_command)
381     return proxy_command->HandleCompletion(
382         input, cursor_index, cursor_char_position, match_start_point,
383         max_return_elements, word_complete, matches);
384   matches.Clear();
385   return 0;
386 }
387 
388 int CommandObjectProxy::HandleArgumentCompletion(
389     Args &input, int &cursor_index, int &cursor_char_position,
390     OptionElementVector &opt_element_vector, int match_start_point,
391     int max_return_elements, bool &word_complete, StringList &matches) {
392   CommandObject *proxy_command = GetProxyCommandObject();
393   if (proxy_command)
394     return proxy_command->HandleArgumentCompletion(
395         input, cursor_index, cursor_char_position, opt_element_vector,
396         match_start_point, max_return_elements, word_complete, matches);
397   matches.Clear();
398   return 0;
399 }
400 
401 const char *CommandObjectProxy::GetRepeatCommand(Args &current_command_args,
402                                                  uint32_t index) {
403   CommandObject *proxy_command = GetProxyCommandObject();
404   if (proxy_command)
405     return proxy_command->GetRepeatCommand(current_command_args, index);
406   return nullptr;
407 }
408 
409 bool CommandObjectProxy::Execute(const char *args_string,
410                                  CommandReturnObject &result) {
411   CommandObject *proxy_command = GetProxyCommandObject();
412   if (proxy_command)
413     return proxy_command->Execute(args_string, result);
414   result.AppendError("command is not implemented");
415   result.SetStatus(eReturnStatusFailed);
416   return false;
417 }
418