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/Options.h"
18 #include "lldb/Interpreter/CommandReturnObject.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 }
36 
37 CommandObjectMultiword::~CommandObjectMultiword() = default;
38 
39 CommandObjectSP
40 CommandObjectMultiword::GetSubcommandSP (const char *sub_cmd, StringList *matches)
41 {
42     CommandObjectSP return_cmd_sp;
43     CommandObject::CommandMap::iterator pos;
44 
45     if (!m_subcommand_dict.empty())
46     {
47         pos = m_subcommand_dict.find (sub_cmd);
48         if (pos != m_subcommand_dict.end()) {
49             // An exact match; append the sub_cmd to the 'matches' string list.
50             if (matches)
51                 matches->AppendString(sub_cmd);
52             return_cmd_sp = pos->second;
53         }
54         else
55         {
56             StringList local_matches;
57             if (matches == nullptr)
58                 matches = &local_matches;
59             int num_matches = AddNamesMatchingPartialString (m_subcommand_dict, sub_cmd, *matches);
60 
61             if (num_matches == 1)
62             {
63                 // Cleaner, but slightly less efficient would be to call back into this function, since I now
64                 // know I have an exact match...
65 
66                 sub_cmd = matches->GetStringAtIndex(0);
67                 pos = m_subcommand_dict.find(sub_cmd);
68                 if (pos != m_subcommand_dict.end())
69                     return_cmd_sp = pos->second;
70             }
71         }
72     }
73     return return_cmd_sp;
74 }
75 
76 CommandObject *
77 CommandObjectMultiword::GetSubcommandObject (const char *sub_cmd, StringList *matches)
78 {
79     return GetSubcommandSP(sub_cmd, matches).get();
80 }
81 
82 bool
83 CommandObjectMultiword::LoadSubCommand(const char *name,
84                                        const CommandObjectSP& cmd_obj)
85 {
86     if (cmd_obj)
87         assert((&GetCommandInterpreter() == &cmd_obj->GetCommandInterpreter()) && "tried to add a CommandObject from a different interpreter");
88 
89     CommandMap::iterator pos;
90     bool success = true;
91 
92     pos = m_subcommand_dict.find(name);
93     if (pos == m_subcommand_dict.end())
94     {
95         m_subcommand_dict[name] = cmd_obj;
96     }
97     else
98         success = false;
99 
100     return success;
101 }
102 
103 bool
104 CommandObjectMultiword::Execute(const char *args_string, CommandReturnObject &result)
105 {
106     Args args (args_string);
107     const size_t argc = args.GetArgumentCount();
108     if (argc == 0)
109     {
110         this->CommandObject::GenerateHelpText (result);
111     }
112     else
113     {
114         const char *sub_command = args.GetArgumentAtIndex (0);
115 
116         if (sub_command)
117         {
118             if (::strcasecmp (sub_command, "help") == 0)
119             {
120                 this->CommandObject::GenerateHelpText (result);
121             }
122             else if (!m_subcommand_dict.empty())
123             {
124                 StringList matches;
125                 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
126                 if (sub_cmd_obj != nullptr)
127                 {
128                     // Now call CommandObject::Execute to process and options in 'rest_of_line'.  From there
129                     // the command-specific version of Execute will be called, with the processed arguments.
130 
131                     args.Shift();
132 
133                     sub_cmd_obj->Execute (args_string, result);
134                 }
135                 else
136                 {
137                     std::string error_msg;
138                     const size_t num_subcmd_matches = matches.GetSize();
139                     if (num_subcmd_matches > 0)
140                         error_msg.assign ("ambiguous command ");
141                     else
142                         error_msg.assign ("invalid command ");
143 
144                     error_msg.append ("'");
145                     error_msg.append (GetCommandName());
146                     error_msg.append (" ");
147                     error_msg.append (sub_command);
148                     error_msg.append ("'.");
149 
150                     if (num_subcmd_matches > 0)
151                     {
152                         error_msg.append (" Possible completions:");
153                         for (size_t i = 0; i < num_subcmd_matches; i++)
154                         {
155                             error_msg.append ("\n\t");
156                             error_msg.append (matches.GetStringAtIndex (i));
157                         }
158                     }
159                     error_msg.append ("\n");
160                     result.AppendRawError (error_msg.c_str());
161                     result.SetStatus (eReturnStatusFailed);
162                 }
163             }
164             else
165             {
166                 result.AppendErrorWithFormat ("'%s' does not have any subcommands.\n", GetCommandName());
167                 result.SetStatus (eReturnStatusFailed);
168             }
169         }
170     }
171 
172     return result.Succeeded();
173 }
174 
175 void
176 CommandObjectMultiword::GenerateHelpText (Stream &output_stream)
177 {
178     // First time through here, generate the help text for the object and
179     // push it to the return result object as well
180 
181     CommandObject::GenerateHelpText(output_stream);
182     output_stream.PutCString("\nThe following subcommands are supported:\n\n");
183 
184     CommandMap::iterator pos;
185     uint32_t max_len = FindLongestCommandWord (m_subcommand_dict);
186 
187     if (max_len)
188         max_len += 4; // Indent the output by 4 spaces.
189 
190     for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
191     {
192         std::string indented_command ("    ");
193         indented_command.append (pos->first);
194         if (pos->second->WantsRawCommandString ())
195         {
196             std::string help_text (pos->second->GetHelp());
197             help_text.append("  Expects 'raw' input (see 'help raw-input'.)");
198             m_interpreter.OutputFormattedHelpText (output_stream,
199                                                    indented_command.c_str(),
200                                                    "--",
201                                                    help_text.c_str(),
202                                                    max_len);
203         }
204         else
205             m_interpreter.OutputFormattedHelpText (output_stream,
206                                                    indented_command.c_str(),
207                                                    "--",
208                                                    pos->second->GetHelp(),
209                                                    max_len);
210     }
211 
212     output_stream.PutCString ("\nFor more help on any particular subcommand, type 'help <command> <subcommand>'.\n");
213 }
214 
215 int
216 CommandObjectMultiword::HandleCompletion(Args &input,
217                                          int &cursor_index,
218                                          int &cursor_char_position,
219                                          int match_start_point,
220                                          int max_return_elements,
221                                          bool &word_complete,
222                                          StringList &matches)
223 {
224     // Any of the command matches will provide a complete word, otherwise the individual
225     // completers will override this.
226     word_complete = true;
227 
228     const char *arg0 = input.GetArgumentAtIndex(0);
229     if (cursor_index == 0)
230     {
231         AddNamesMatchingPartialString (m_subcommand_dict,
232                                        arg0,
233                                        matches);
234 
235         if (matches.GetSize() == 1
236             && matches.GetStringAtIndex(0) != nullptr
237             && strcmp (arg0, matches.GetStringAtIndex(0)) == 0)
238         {
239             StringList temp_matches;
240             CommandObject *cmd_obj = GetSubcommandObject (arg0,
241                                                           &temp_matches);
242             if (cmd_obj != nullptr)
243             {
244                 if (input.GetArgumentCount() == 1)
245                 {
246                     word_complete = true;
247                 }
248                 else
249                 {
250                     matches.DeleteStringAtIndex (0);
251                     input.Shift();
252                     cursor_char_position = 0;
253                     input.AppendArgument ("");
254                     return cmd_obj->HandleCompletion (input,
255                                                       cursor_index,
256                                                       cursor_char_position,
257                                                       match_start_point,
258                                                       max_return_elements,
259                                                       word_complete,
260                                                       matches);
261                 }
262             }
263         }
264         return matches.GetSize();
265     }
266     else
267     {
268         CommandObject *sub_command_object = GetSubcommandObject (arg0,
269                                                                  &matches);
270         if (sub_command_object == nullptr)
271         {
272             return matches.GetSize();
273         }
274         else
275         {
276             // Remove the one match that we got from calling GetSubcommandObject.
277             matches.DeleteStringAtIndex(0);
278             input.Shift();
279             cursor_index--;
280             return sub_command_object->HandleCompletion (input,
281                                                          cursor_index,
282                                                          cursor_char_position,
283                                                          match_start_point,
284                                                          max_return_elements,
285                                                          word_complete,
286                                                          matches);
287         }
288     }
289 }
290 
291 const char *
292 CommandObjectMultiword::GetRepeatCommand (Args &current_command_args, uint32_t index)
293 {
294     index++;
295     if (current_command_args.GetArgumentCount() <= index)
296         return nullptr;
297     CommandObject *sub_command_object = GetSubcommandObject (current_command_args.GetArgumentAtIndex(index));
298     if (sub_command_object == nullptr)
299         return nullptr;
300     return sub_command_object->GetRepeatCommand(current_command_args, index);
301 }
302 
303 void
304 CommandObjectMultiword::AproposAllSubCommands (const char *prefix,
305                                                const char *search_word,
306                                                StringList &commands_found,
307                                                StringList &commands_help)
308 {
309     CommandObject::CommandMap::const_iterator pos;
310 
311     for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
312     {
313         const char * command_name = pos->first.c_str();
314         CommandObject *sub_cmd_obj = pos->second.get();
315         StreamString complete_command_name;
316 
317         complete_command_name.Printf ("%s %s", prefix, command_name);
318 
319         if (sub_cmd_obj->HelpTextContainsWord (search_word))
320         {
321             commands_found.AppendString (complete_command_name.GetData());
322             commands_help.AppendString (sub_cmd_obj->GetHelp());
323         }
324 
325         if (sub_cmd_obj->IsMultiwordObject())
326             sub_cmd_obj->AproposAllSubCommands (complete_command_name.GetData(),
327                                                 search_word,
328                                                 commands_found,
329                                                 commands_help);
330     }
331 }
332 
333 CommandObjectProxy::CommandObjectProxy (CommandInterpreter &interpreter,
334                                         const char *name,
335                                         const char *help,
336                                         const char *syntax,
337                                         uint32_t flags) :
338     CommandObject (interpreter, name, help, syntax, flags)
339 {
340 }
341 
342 CommandObjectProxy::~CommandObjectProxy() = default;
343 
344 const char *
345 CommandObjectProxy::GetHelpLong ()
346 {
347     CommandObject *proxy_command = GetProxyCommandObject();
348     if (proxy_command)
349         return proxy_command->GetHelpLong();
350     return nullptr;
351 }
352 
353 bool
354 CommandObjectProxy::IsRemovable() const
355 {
356     const CommandObject *proxy_command = const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
357     if (proxy_command)
358         return proxy_command->IsRemovable();
359     return false;
360 }
361 
362 bool
363 CommandObjectProxy::IsMultiwordObject ()
364 {
365     CommandObject *proxy_command = GetProxyCommandObject();
366     if (proxy_command)
367         return proxy_command->IsMultiwordObject();
368     return false;
369 }
370 
371 CommandObjectMultiword*
372 CommandObjectProxy::GetAsMultiwordCommand ()
373 {
374     CommandObject *proxy_command = GetProxyCommandObject();
375     if (proxy_command)
376         return proxy_command->GetAsMultiwordCommand();
377     return nullptr;
378 }
379 
380 void
381 CommandObjectProxy::GenerateHelpText (Stream &result)
382 {
383     CommandObject *proxy_command = GetProxyCommandObject();
384     if (proxy_command)
385         return proxy_command->GenerateHelpText(result);
386 }
387 
388 lldb::CommandObjectSP
389 CommandObjectProxy::GetSubcommandSP (const char *sub_cmd, StringList *matches)
390 {
391     CommandObject *proxy_command = GetProxyCommandObject();
392     if (proxy_command)
393         return proxy_command->GetSubcommandSP(sub_cmd, matches);
394     return lldb::CommandObjectSP();
395 }
396 
397 CommandObject *
398 CommandObjectProxy::GetSubcommandObject (const char *sub_cmd, StringList *matches)
399 {
400     CommandObject *proxy_command = GetProxyCommandObject();
401     if (proxy_command)
402         return proxy_command->GetSubcommandObject(sub_cmd, matches);
403     return nullptr;
404 }
405 
406 void
407 CommandObjectProxy::AproposAllSubCommands (const char *prefix,
408                                            const char *search_word,
409                                            StringList &commands_found,
410                                            StringList &commands_help)
411 {
412     CommandObject *proxy_command = GetProxyCommandObject();
413     if (proxy_command)
414         return proxy_command->AproposAllSubCommands (prefix,
415                                                      search_word,
416                                                      commands_found,
417                                                      commands_help);
418 }
419 
420 bool
421 CommandObjectProxy::LoadSubCommand (const char *cmd_name,
422                                     const lldb::CommandObjectSP& command_sp)
423 {
424     CommandObject *proxy_command = GetProxyCommandObject();
425     if (proxy_command)
426         return proxy_command->LoadSubCommand (cmd_name, command_sp);
427     return false;
428 }
429 
430 bool
431 CommandObjectProxy::WantsRawCommandString()
432 {
433     CommandObject *proxy_command = GetProxyCommandObject();
434     if (proxy_command)
435         return proxy_command->WantsRawCommandString();
436     return false;
437 }
438 
439 bool
440 CommandObjectProxy::WantsCompletion()
441 {
442     CommandObject *proxy_command = GetProxyCommandObject();
443     if (proxy_command)
444         return proxy_command->WantsCompletion();
445     return false;
446 }
447 
448 Options *
449 CommandObjectProxy::GetOptions ()
450 {
451     CommandObject *proxy_command = GetProxyCommandObject();
452     if (proxy_command)
453         return proxy_command->GetOptions ();
454     return nullptr;
455 }
456 
457 int
458 CommandObjectProxy::HandleCompletion (Args &input,
459                                       int &cursor_index,
460                                       int &cursor_char_position,
461                                       int match_start_point,
462                                       int max_return_elements,
463                                       bool &word_complete,
464                                       StringList &matches)
465 {
466     CommandObject *proxy_command = GetProxyCommandObject();
467     if (proxy_command)
468         return proxy_command->HandleCompletion (input,
469                                                 cursor_index,
470                                                 cursor_char_position,
471                                                 match_start_point,
472                                                 max_return_elements,
473                                                 word_complete,
474                                                 matches);
475     matches.Clear();
476     return 0;
477 }
478 
479 int
480 CommandObjectProxy::HandleArgumentCompletion (Args &input,
481                                               int &cursor_index,
482                                               int &cursor_char_position,
483                                               OptionElementVector &opt_element_vector,
484                                               int match_start_point,
485                                               int max_return_elements,
486                                               bool &word_complete,
487                                               StringList &matches)
488 {
489     CommandObject *proxy_command = GetProxyCommandObject();
490     if (proxy_command)
491         return proxy_command->HandleArgumentCompletion (input,
492                                                         cursor_index,
493                                                         cursor_char_position,
494                                                         opt_element_vector,
495                                                         match_start_point,
496                                                         max_return_elements,
497                                                         word_complete,
498                                                         matches);
499     matches.Clear();
500     return 0;
501 }
502 
503 const char *
504 CommandObjectProxy::GetRepeatCommand (Args &current_command_args,
505                                       uint32_t index)
506 {
507     CommandObject *proxy_command = GetProxyCommandObject();
508     if (proxy_command)
509         return proxy_command->GetRepeatCommand (current_command_args, index);
510     return nullptr;
511 }
512 
513 bool
514 CommandObjectProxy::Execute (const char *args_string,
515                              CommandReturnObject &result)
516 {
517     CommandObject *proxy_command = GetProxyCommandObject();
518     if (proxy_command)
519         return proxy_command->Execute (args_string, result);
520     result.AppendError ("command is not implemented");
521     result.SetStatus (eReturnStatusFailed);
522     return false;
523 }
524