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 {
37 }
38 
39 CommandObjectMultiword::~CommandObjectMultiword ()
40 {
41 }
42 
43 CommandObjectSP
44 CommandObjectMultiword::GetSubcommandSP (const char *sub_cmd, StringList *matches)
45 {
46     CommandObjectSP return_cmd_sp;
47     CommandObject::CommandMap::iterator pos;
48 
49     if (!m_subcommand_dict.empty())
50     {
51         pos = m_subcommand_dict.find (sub_cmd);
52         if (pos != m_subcommand_dict.end()) {
53             // An exact match; append the sub_cmd to the 'matches' string list.
54             if (matches)
55                 matches->AppendString(sub_cmd);
56             return_cmd_sp = pos->second;
57         }
58         else
59         {
60 
61             StringList local_matches;
62             if (matches == NULL)
63                 matches = &local_matches;
64             int num_matches = CommandObject::AddNamesMatchingPartialString (m_subcommand_dict, sub_cmd, *matches);
65 
66             if (num_matches == 1)
67             {
68                 // Cleaner, but slightly less efficient would be to call back into this function, since I now
69                 // know I have an exact match...
70 
71                 sub_cmd = matches->GetStringAtIndex(0);
72                 pos = m_subcommand_dict.find(sub_cmd);
73                 if (pos != m_subcommand_dict.end())
74                     return_cmd_sp = pos->second;
75             }
76         }
77     }
78     return return_cmd_sp;
79 }
80 
81 CommandObject *
82 CommandObjectMultiword::GetSubcommandObject (const char *sub_cmd, StringList *matches)
83 {
84     return GetSubcommandSP(sub_cmd, matches).get();
85 }
86 
87 bool
88 CommandObjectMultiword::LoadSubCommand
89 (
90     const char *name,
91     const CommandObjectSP& cmd_obj
92 )
93 {
94     CommandMap::iterator pos;
95     bool success = true;
96 
97     pos = m_subcommand_dict.find(name);
98     if (pos == m_subcommand_dict.end())
99     {
100         m_subcommand_dict[name] = cmd_obj;
101         m_interpreter.CrossRegisterCommand (name, GetCommandName());
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         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                 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                     int 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 (int 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(), error_msg.size());
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 (CommandReturnObject &result)
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     Stream &output_stream = result.GetOutputStream();
188     output_stream.PutCString ("The following subcommands are supported:\n\n");
189 
190     CommandMap::iterator pos;
191     uint32_t max_len = m_interpreter.FindLongestCommandWord (m_subcommand_dict);
192 
193     if (max_len)
194         max_len += 4; // Indent the output by 4 spaces.
195 
196     for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
197     {
198         std::string indented_command ("    ");
199         indented_command.append (pos->first);
200         if (pos->second->WantsRawCommandString ())
201         {
202             std::string help_text (pos->second->GetHelp());
203             help_text.append ("  This command takes 'raw' input (no need to quote stuff).");
204             m_interpreter.OutputFormattedHelpText (result.GetOutputStream(),
205                                                    indented_command.c_str(),
206                                                    "--",
207                                                    help_text.c_str(),
208                                                    max_len);
209         }
210         else
211             m_interpreter.OutputFormattedHelpText (result.GetOutputStream(),
212                                                    indented_command.c_str(),
213                                                    "--",
214                                                    pos->second->GetHelp(),
215                                                    max_len);
216     }
217 
218     output_stream.PutCString ("\nFor more help on any particular subcommand, type 'help <command> <subcommand>'.\n");
219 
220     result.SetStatus (eReturnStatusSuccessFinishNoResult);
221 }
222 
223 int
224 CommandObjectMultiword::HandleCompletion
225 (
226     Args &input,
227     int &cursor_index,
228     int &cursor_char_position,
229     int match_start_point,
230     int max_return_elements,
231     bool &word_complete,
232     StringList &matches
233 )
234 {
235     // Any of the command matches will provide a complete word, otherwise the individual
236     // completers will override this.
237     word_complete = true;
238 
239     if (cursor_index == 0)
240     {
241         CommandObject::AddNamesMatchingPartialString (m_subcommand_dict,
242                                                       input.GetArgumentAtIndex(0),
243                                                       matches);
244 
245         if (matches.GetSize() == 1
246             && matches.GetStringAtIndex(0) != NULL
247             && strcmp (input.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0)
248         {
249             StringList temp_matches;
250             CommandObject *cmd_obj = GetSubcommandObject (input.GetArgumentAtIndex(0),
251                                                           &temp_matches);
252             if (cmd_obj != NULL)
253             {
254                 matches.DeleteStringAtIndex (0);
255                 input.Shift();
256                 cursor_char_position = 0;
257                 input.AppendArgument ("");
258                 return cmd_obj->HandleCompletion (input,
259                                                   cursor_index,
260                                                   cursor_char_position,
261                                                   match_start_point,
262                                                   max_return_elements,
263                                                   word_complete,
264                                                   matches);
265             }
266             else
267                 return matches.GetSize();
268         }
269         else
270             return matches.GetSize();
271     }
272     else
273     {
274         CommandObject *sub_command_object = GetSubcommandObject (input.GetArgumentAtIndex(0),
275                                                                  &matches);
276         if (sub_command_object == NULL)
277         {
278             return matches.GetSize();
279         }
280         else
281         {
282             // Remove the one match that we got from calling GetSubcommandObject.
283             matches.DeleteStringAtIndex(0);
284             input.Shift();
285             cursor_index--;
286             return sub_command_object->HandleCompletion (input,
287                                                          cursor_index,
288                                                          cursor_char_position,
289                                                          match_start_point,
290                                                          max_return_elements,
291                                                          word_complete,
292                                                          matches);
293         }
294 
295     }
296 }
297 
298 const char *
299 CommandObjectMultiword::GetRepeatCommand (Args &current_command_args, uint32_t index)
300 {
301     index++;
302     if (current_command_args.GetArgumentCount() <= index)
303         return NULL;
304     CommandObject *sub_command_object = GetSubcommandObject (current_command_args.GetArgumentAtIndex(index));
305     if (sub_command_object == NULL)
306         return NULL;
307     return sub_command_object->GetRepeatCommand(current_command_args, index);
308 }
309 
310 
311 void
312 CommandObjectMultiword::AproposAllSubCommands (const char *prefix,
313                                                const char *search_word,
314                                                StringList &commands_found,
315                                                StringList &commands_help)
316 {
317     CommandObject::CommandMap::const_iterator pos;
318 
319     for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
320     {
321         const char * command_name = pos->first.c_str();
322         CommandObject *sub_cmd_obj = pos->second.get();
323         StreamString complete_command_name;
324 
325         complete_command_name.Printf ("%s %s", prefix, command_name);
326 
327         if (sub_cmd_obj->HelpTextContainsWord (search_word))
328         {
329             commands_found.AppendString (complete_command_name.GetData());
330             commands_help.AppendString (sub_cmd_obj->GetHelp());
331         }
332 
333         if (sub_cmd_obj->IsMultiwordObject())
334             sub_cmd_obj->AproposAllSubCommands (complete_command_name.GetData(),
335                                                 search_word,
336                                                 commands_found,
337                                                 commands_help);
338     }
339 }
340 
341 
342 
343 CommandObjectProxy::CommandObjectProxy (CommandInterpreter &interpreter,
344                                         const char *name,
345                                         const char *help,
346                                         const char *syntax,
347                                         uint32_t flags) :
348     CommandObject (interpreter, name, help, syntax, flags)
349 {
350 }
351 
352 CommandObjectProxy::~CommandObjectProxy ()
353 {
354 }
355 
356 const char *
357 CommandObjectProxy::GetHelpLong ()
358 {
359     CommandObject *proxy_command = GetProxyCommandObject();
360     if (proxy_command)
361         return proxy_command->GetHelpLong();
362     return NULL;
363 }
364 
365 void
366 CommandObjectProxy::AddObject (const char *obj_name)
367 {
368     CommandObject *proxy_command = GetProxyCommandObject();
369     if (proxy_command)
370         return proxy_command->AddObject (obj_name);
371 }
372 
373 bool
374 CommandObjectProxy::IsCrossRefObject ()
375 {
376     CommandObject *proxy_command = GetProxyCommandObject();
377     if (proxy_command)
378         return proxy_command->IsCrossRefObject();
379     return false;
380 }
381 
382 bool
383 CommandObjectProxy::IsRemovable() const
384 {
385     const CommandObject *proxy_command = const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
386     if (proxy_command)
387         return proxy_command->IsRemovable();
388     return false;
389 }
390 
391 bool
392 CommandObjectProxy::IsMultiwordObject ()
393 {
394     CommandObject *proxy_command = GetProxyCommandObject();
395     if (proxy_command)
396         return proxy_command->IsMultiwordObject();
397     return false;
398 }
399 
400 lldb::CommandObjectSP
401 CommandObjectProxy::GetSubcommandSP (const char *sub_cmd, StringList *matches)
402 {
403     CommandObject *proxy_command = GetProxyCommandObject();
404     if (proxy_command)
405         return proxy_command->GetSubcommandSP(sub_cmd, matches);
406     return lldb::CommandObjectSP();
407 }
408 
409 CommandObject *
410 CommandObjectProxy::GetSubcommandObject (const char *sub_cmd, StringList *matches)
411 {
412     CommandObject *proxy_command = GetProxyCommandObject();
413     if (proxy_command)
414         return proxy_command->GetSubcommandObject(sub_cmd, matches);
415     return NULL;
416 }
417 
418 void
419 CommandObjectProxy::AproposAllSubCommands (const char *prefix,
420                                            const char *search_word,
421                                            StringList &commands_found,
422                                            StringList &commands_help)
423 {
424     CommandObject *proxy_command = GetProxyCommandObject();
425     if (proxy_command)
426         return proxy_command->AproposAllSubCommands (prefix,
427                                                      search_word,
428                                                      commands_found,
429                                                      commands_help);
430 }
431 
432 bool
433 CommandObjectProxy::LoadSubCommand (const char *cmd_name,
434                                     const lldb::CommandObjectSP& command_sp)
435 {
436     CommandObject *proxy_command = GetProxyCommandObject();
437     if (proxy_command)
438         return proxy_command->LoadSubCommand (cmd_name, command_sp);
439     return false;
440 }
441 
442 bool
443 CommandObjectProxy::WantsRawCommandString()
444 {
445     CommandObject *proxy_command = GetProxyCommandObject();
446     if (proxy_command)
447         return proxy_command->WantsRawCommandString();
448     return false;
449 }
450 
451 bool
452 CommandObjectProxy::WantsCompletion()
453 {
454     CommandObject *proxy_command = GetProxyCommandObject();
455     if (proxy_command)
456         return proxy_command->WantsCompletion();
457     return false;
458 }
459 
460 
461 Options *
462 CommandObjectProxy::GetOptions ()
463 {
464     CommandObject *proxy_command = GetProxyCommandObject();
465     if (proxy_command)
466         return proxy_command->GetOptions ();
467     return NULL;
468 }
469 
470 
471 int
472 CommandObjectProxy::HandleCompletion (Args &input,
473                                       int &cursor_index,
474                                       int &cursor_char_position,
475                                       int match_start_point,
476                                       int max_return_elements,
477                                       bool &word_complete,
478                                       StringList &matches)
479 {
480     CommandObject *proxy_command = GetProxyCommandObject();
481     if (proxy_command)
482         return proxy_command->HandleCompletion (input,
483                                                 cursor_index,
484                                                 cursor_char_position,
485                                                 match_start_point,
486                                                 max_return_elements,
487                                                 word_complete,
488                                                 matches);
489     matches.Clear();
490     return 0;
491 }
492 int
493 CommandObjectProxy::HandleArgumentCompletion (Args &input,
494                                               int &cursor_index,
495                                               int &cursor_char_position,
496                                               OptionElementVector &opt_element_vector,
497                                               int match_start_point,
498                                               int max_return_elements,
499                                               bool &word_complete,
500                                               StringList &matches)
501 {
502     CommandObject *proxy_command = GetProxyCommandObject();
503     if (proxy_command)
504         return proxy_command->HandleArgumentCompletion (input,
505                                                         cursor_index,
506                                                         cursor_char_position,
507                                                         opt_element_vector,
508                                                         match_start_point,
509                                                         max_return_elements,
510                                                         word_complete,
511                                                         matches);
512     matches.Clear();
513     return 0;
514 }
515 
516 const char *
517 CommandObjectProxy::GetRepeatCommand (Args &current_command_args,
518                                       uint32_t index)
519 {
520     CommandObject *proxy_command = GetProxyCommandObject();
521     if (proxy_command)
522         return proxy_command->GetRepeatCommand (current_command_args, index);
523     return NULL;
524 }
525 
526 bool
527 CommandObjectProxy::Execute (const char *args_string,
528                              CommandReturnObject &result)
529 {
530     CommandObject *proxy_command = GetProxyCommandObject();
531     if (proxy_command)
532         return proxy_command->Execute (args_string, result);
533     result.AppendError ("command is not implemented");
534     result.SetStatus (eReturnStatusFailed);
535     return false;
536 }
537 
538 
539