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