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