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   } 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().str().c_str());
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(llvm::StringRef());
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 &current_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(llvm::StringRef prefix,
250                                                    llvm::StringRef 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 << prefix << " " << command_name;
261 
262     if (sub_cmd_obj->HelpTextContainsWord(search_word)) {
263       commands_found.AppendString(complete_command_name.GetString());
264       commands_help.AppendString(sub_cmd_obj->GetHelp());
265     }
266 
267     if (sub_cmd_obj->IsMultiwordObject())
268       sub_cmd_obj->AproposAllSubCommands(complete_command_name.GetString(),
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 llvm::StringRef CommandObjectProxy::GetHelpLong() {
282   CommandObject *proxy_command = GetProxyCommandObject();
283   if (proxy_command)
284     return proxy_command->GetHelpLong();
285   return llvm::StringRef();
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
317 CommandObjectProxy::GetSubcommandSP(llvm::StringRef sub_cmd,
318                                     StringList *matches) {
319   CommandObject *proxy_command = GetProxyCommandObject();
320   if (proxy_command)
321     return proxy_command->GetSubcommandSP(sub_cmd, matches);
322   return lldb::CommandObjectSP();
323 }
324 
325 CommandObject *CommandObjectProxy::GetSubcommandObject(llvm::StringRef sub_cmd,
326                                                        StringList *matches) {
327   CommandObject *proxy_command = GetProxyCommandObject();
328   if (proxy_command)
329     return proxy_command->GetSubcommandObject(sub_cmd, matches);
330   return nullptr;
331 }
332 
333 void CommandObjectProxy::AproposAllSubCommands(llvm::StringRef prefix,
334                                                llvm::StringRef search_word,
335                                                StringList &commands_found,
336                                                StringList &commands_help) {
337   CommandObject *proxy_command = GetProxyCommandObject();
338   if (proxy_command)
339     return proxy_command->AproposAllSubCommands(prefix, search_word,
340                                                 commands_found, commands_help);
341 }
342 
343 bool CommandObjectProxy::LoadSubCommand(
344     llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_sp) {
345   CommandObject *proxy_command = GetProxyCommandObject();
346   if (proxy_command)
347     return proxy_command->LoadSubCommand(cmd_name, command_sp);
348   return false;
349 }
350 
351 bool CommandObjectProxy::WantsRawCommandString() {
352   CommandObject *proxy_command = GetProxyCommandObject();
353   if (proxy_command)
354     return proxy_command->WantsRawCommandString();
355   return false;
356 }
357 
358 bool CommandObjectProxy::WantsCompletion() {
359   CommandObject *proxy_command = GetProxyCommandObject();
360   if (proxy_command)
361     return proxy_command->WantsCompletion();
362   return false;
363 }
364 
365 Options *CommandObjectProxy::GetOptions() {
366   CommandObject *proxy_command = GetProxyCommandObject();
367   if (proxy_command)
368     return proxy_command->GetOptions();
369   return nullptr;
370 }
371 
372 int CommandObjectProxy::HandleCompletion(Args &input, int &cursor_index,
373                                          int &cursor_char_position,
374                                          int match_start_point,
375                                          int max_return_elements,
376                                          bool &word_complete,
377                                          StringList &matches) {
378   CommandObject *proxy_command = GetProxyCommandObject();
379   if (proxy_command)
380     return proxy_command->HandleCompletion(
381         input, cursor_index, cursor_char_position, match_start_point,
382         max_return_elements, word_complete, matches);
383   matches.Clear();
384   return 0;
385 }
386 
387 int CommandObjectProxy::HandleArgumentCompletion(
388     Args &input, int &cursor_index, int &cursor_char_position,
389     OptionElementVector &opt_element_vector, int match_start_point,
390     int max_return_elements, bool &word_complete, StringList &matches) {
391   CommandObject *proxy_command = GetProxyCommandObject();
392   if (proxy_command)
393     return proxy_command->HandleArgumentCompletion(
394         input, cursor_index, cursor_char_position, opt_element_vector,
395         match_start_point, max_return_elements, word_complete, matches);
396   matches.Clear();
397   return 0;
398 }
399 
400 const char *CommandObjectProxy::GetRepeatCommand(Args &current_command_args,
401                                                  uint32_t index) {
402   CommandObject *proxy_command = GetProxyCommandObject();
403   if (proxy_command)
404     return proxy_command->GetRepeatCommand(current_command_args, index);
405   return nullptr;
406 }
407 
408 bool CommandObjectProxy::Execute(const char *args_string,
409                                  CommandReturnObject &result) {
410   CommandObject *proxy_command = GetProxyCommandObject();
411   if (proxy_command)
412     return proxy_command->Execute(args_string, result);
413   result.AppendError("command is not implemented");
414   result.SetStatus(eReturnStatusFailed);
415   return false;
416 }
417