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