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     if (cmd_obj.get())
96         assert((&GetCommandInterpreter() == &cmd_obj->GetCommandInterpreter()) && "tried to add a CommandObject from a different interpreter");
97 
98     CommandMap::iterator pos;
99     bool success = true;
100 
101     pos = m_subcommand_dict.find(name);
102     if (pos == m_subcommand_dict.end())
103     {
104         m_subcommand_dict[name] = cmd_obj;
105     }
106     else
107         success = false;
108 
109     return success;
110 }
111 
112 bool
113 CommandObjectMultiword::Execute(const char *args_string, CommandReturnObject &result)
114 {
115     Args args (args_string);
116     const size_t argc = args.GetArgumentCount();
117     if (argc == 0)
118     {
119         this->CommandObject::GenerateHelpText (result);
120     }
121     else
122     {
123         const char *sub_command = args.GetArgumentAtIndex (0);
124 
125         if (sub_command)
126         {
127             if (::strcasecmp (sub_command, "help") == 0)
128             {
129                 this->CommandObject::GenerateHelpText (result);
130             }
131             else if (!m_subcommand_dict.empty())
132             {
133                 StringList matches;
134                 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
135                 if (sub_cmd_obj != NULL)
136                 {
137                     // Now call CommandObject::Execute to process and options in 'rest_of_line'.  From there
138                     // the command-specific version of Execute will be called, with the processed arguments.
139 
140                     args.Shift();
141 
142                     sub_cmd_obj->Execute (args_string, result);
143                 }
144                 else
145                 {
146                     std::string error_msg;
147                     const size_t num_subcmd_matches = matches.GetSize();
148                     if (num_subcmd_matches > 0)
149                         error_msg.assign ("ambiguous command ");
150                     else
151                         error_msg.assign ("invalid command ");
152 
153                     error_msg.append ("'");
154                     error_msg.append (GetCommandName());
155                     error_msg.append (" ");
156                     error_msg.append (sub_command);
157                     error_msg.append ("'.");
158 
159                     if (num_subcmd_matches > 0)
160                     {
161                         error_msg.append (" Possible completions:");
162                         for (size_t i = 0; i < num_subcmd_matches; i++)
163                         {
164                             error_msg.append ("\n\t");
165                             error_msg.append (matches.GetStringAtIndex (i));
166                         }
167                     }
168                     error_msg.append ("\n");
169                     result.AppendRawError (error_msg.c_str());
170                     result.SetStatus (eReturnStatusFailed);
171                 }
172             }
173             else
174             {
175                 result.AppendErrorWithFormat ("'%s' does not have any subcommands.\n", GetCommandName());
176                 result.SetStatus (eReturnStatusFailed);
177             }
178         }
179     }
180 
181     return result.Succeeded();
182 }
183 
184 void
185 CommandObjectMultiword::GenerateHelpText (Stream &output_stream)
186 {
187     // First time through here, generate the help text for the object and
188     // push it to the return result object as well
189 
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 (output_stream,
207                                                    indented_command.c_str(),
208                                                    "--",
209                                                    help_text.c_str(),
210                                                    max_len);
211         }
212         else
213             m_interpreter.OutputFormattedHelpText (output_stream,
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 
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     const char *arg0 = input.GetArgumentAtIndex(0);
240     if (cursor_index == 0)
241     {
242         CommandObject::AddNamesMatchingPartialString (m_subcommand_dict,
243                                                       arg0,
244                                                       matches);
245 
246         if (matches.GetSize() == 1
247             && matches.GetStringAtIndex(0) != NULL
248             && strcmp (arg0, matches.GetStringAtIndex(0)) == 0)
249         {
250             StringList temp_matches;
251             CommandObject *cmd_obj = GetSubcommandObject (arg0,
252                                                           &temp_matches);
253             if (cmd_obj != NULL)
254             {
255                 if (input.GetArgumentCount() == 1)
256                 {
257                     word_complete = true;
258                 }
259                 else
260                 {
261                     matches.DeleteStringAtIndex (0);
262                     input.Shift();
263                     cursor_char_position = 0;
264                     input.AppendArgument ("");
265                     return cmd_obj->HandleCompletion (input,
266                                                       cursor_index,
267                                                       cursor_char_position,
268                                                       match_start_point,
269                                                       max_return_elements,
270                                                       word_complete,
271                                                       matches);
272                 }
273             }
274         }
275         return matches.GetSize();
276     }
277     else
278     {
279         CommandObject *sub_command_object = GetSubcommandObject (arg0,
280                                                                  &matches);
281         if (sub_command_object == NULL)
282         {
283             return matches.GetSize();
284         }
285         else
286         {
287             // Remove the one match that we got from calling GetSubcommandObject.
288             matches.DeleteStringAtIndex(0);
289             input.Shift();
290             cursor_index--;
291             return sub_command_object->HandleCompletion (input,
292                                                          cursor_index,
293                                                          cursor_char_position,
294                                                          match_start_point,
295                                                          max_return_elements,
296                                                          word_complete,
297                                                          matches);
298         }
299 
300     }
301 }
302 
303 const char *
304 CommandObjectMultiword::GetRepeatCommand (Args &current_command_args, uint32_t index)
305 {
306     index++;
307     if (current_command_args.GetArgumentCount() <= index)
308         return NULL;
309     CommandObject *sub_command_object = GetSubcommandObject (current_command_args.GetArgumentAtIndex(index));
310     if (sub_command_object == NULL)
311         return NULL;
312     return sub_command_object->GetRepeatCommand(current_command_args, index);
313 }
314 
315 
316 void
317 CommandObjectMultiword::AproposAllSubCommands (const char *prefix,
318                                                const char *search_word,
319                                                StringList &commands_found,
320                                                StringList &commands_help)
321 {
322     CommandObject::CommandMap::const_iterator pos;
323 
324     for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
325     {
326         const char * command_name = pos->first.c_str();
327         CommandObject *sub_cmd_obj = pos->second.get();
328         StreamString complete_command_name;
329 
330         complete_command_name.Printf ("%s %s", prefix, command_name);
331 
332         if (sub_cmd_obj->HelpTextContainsWord (search_word))
333         {
334             commands_found.AppendString (complete_command_name.GetData());
335             commands_help.AppendString (sub_cmd_obj->GetHelp());
336         }
337 
338         if (sub_cmd_obj->IsMultiwordObject())
339             sub_cmd_obj->AproposAllSubCommands (complete_command_name.GetData(),
340                                                 search_word,
341                                                 commands_found,
342                                                 commands_help);
343     }
344 }
345 
346 
347 
348 CommandObjectProxy::CommandObjectProxy (CommandInterpreter &interpreter,
349                                         const char *name,
350                                         const char *help,
351                                         const char *syntax,
352                                         uint32_t flags) :
353     CommandObject (interpreter, name, help, syntax, flags)
354 {
355 }
356 
357 CommandObjectProxy::~CommandObjectProxy ()
358 {
359 }
360 
361 const char *
362 CommandObjectProxy::GetHelpLong ()
363 {
364     CommandObject *proxy_command = GetProxyCommandObject();
365     if (proxy_command)
366         return proxy_command->GetHelpLong();
367     return NULL;
368 }
369 
370 bool
371 CommandObjectProxy::IsRemovable() const
372 {
373     const CommandObject *proxy_command = const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
374     if (proxy_command)
375         return proxy_command->IsRemovable();
376     return false;
377 }
378 
379 bool
380 CommandObjectProxy::IsMultiwordObject ()
381 {
382     CommandObject *proxy_command = GetProxyCommandObject();
383     if (proxy_command)
384         return proxy_command->IsMultiwordObject();
385     return false;
386 }
387 
388 void
389 CommandObjectProxy::GenerateHelpText (Stream &result)
390 {
391     CommandObject *proxy_command = GetProxyCommandObject();
392     if (proxy_command)
393         return proxy_command->GenerateHelpText(result);
394 }
395 
396 lldb::CommandObjectSP
397 CommandObjectProxy::GetSubcommandSP (const char *sub_cmd, StringList *matches)
398 {
399     CommandObject *proxy_command = GetProxyCommandObject();
400     if (proxy_command)
401         return proxy_command->GetSubcommandSP(sub_cmd, matches);
402     return lldb::CommandObjectSP();
403 }
404 
405 CommandObject *
406 CommandObjectProxy::GetSubcommandObject (const char *sub_cmd, StringList *matches)
407 {
408     CommandObject *proxy_command = GetProxyCommandObject();
409     if (proxy_command)
410         return proxy_command->GetSubcommandObject(sub_cmd, matches);
411     return NULL;
412 }
413 
414 void
415 CommandObjectProxy::AproposAllSubCommands (const char *prefix,
416                                            const char *search_word,
417                                            StringList &commands_found,
418                                            StringList &commands_help)
419 {
420     CommandObject *proxy_command = GetProxyCommandObject();
421     if (proxy_command)
422         return proxy_command->AproposAllSubCommands (prefix,
423                                                      search_word,
424                                                      commands_found,
425                                                      commands_help);
426 }
427 
428 bool
429 CommandObjectProxy::LoadSubCommand (const char *cmd_name,
430                                     const lldb::CommandObjectSP& command_sp)
431 {
432     CommandObject *proxy_command = GetProxyCommandObject();
433     if (proxy_command)
434         return proxy_command->LoadSubCommand (cmd_name, command_sp);
435     return false;
436 }
437 
438 bool
439 CommandObjectProxy::WantsRawCommandString()
440 {
441     CommandObject *proxy_command = GetProxyCommandObject();
442     if (proxy_command)
443         return proxy_command->WantsRawCommandString();
444     return false;
445 }
446 
447 bool
448 CommandObjectProxy::WantsCompletion()
449 {
450     CommandObject *proxy_command = GetProxyCommandObject();
451     if (proxy_command)
452         return proxy_command->WantsCompletion();
453     return false;
454 }
455 
456 
457 Options *
458 CommandObjectProxy::GetOptions ()
459 {
460     CommandObject *proxy_command = GetProxyCommandObject();
461     if (proxy_command)
462         return proxy_command->GetOptions ();
463     return NULL;
464 }
465 
466 
467 int
468 CommandObjectProxy::HandleCompletion (Args &input,
469                                       int &cursor_index,
470                                       int &cursor_char_position,
471                                       int match_start_point,
472                                       int max_return_elements,
473                                       bool &word_complete,
474                                       StringList &matches)
475 {
476     CommandObject *proxy_command = GetProxyCommandObject();
477     if (proxy_command)
478         return proxy_command->HandleCompletion (input,
479                                                 cursor_index,
480                                                 cursor_char_position,
481                                                 match_start_point,
482                                                 max_return_elements,
483                                                 word_complete,
484                                                 matches);
485     matches.Clear();
486     return 0;
487 }
488 int
489 CommandObjectProxy::HandleArgumentCompletion (Args &input,
490                                               int &cursor_index,
491                                               int &cursor_char_position,
492                                               OptionElementVector &opt_element_vector,
493                                               int match_start_point,
494                                               int max_return_elements,
495                                               bool &word_complete,
496                                               StringList &matches)
497 {
498     CommandObject *proxy_command = GetProxyCommandObject();
499     if (proxy_command)
500         return proxy_command->HandleArgumentCompletion (input,
501                                                         cursor_index,
502                                                         cursor_char_position,
503                                                         opt_element_vector,
504                                                         match_start_point,
505                                                         max_return_elements,
506                                                         word_complete,
507                                                         matches);
508     matches.Clear();
509     return 0;
510 }
511 
512 const char *
513 CommandObjectProxy::GetRepeatCommand (Args &current_command_args,
514                                       uint32_t index)
515 {
516     CommandObject *proxy_command = GetProxyCommandObject();
517     if (proxy_command)
518         return proxy_command->GetRepeatCommand (current_command_args, index);
519     return NULL;
520 }
521 
522 bool
523 CommandObjectProxy::Execute (const char *args_string,
524                              CommandReturnObject &result)
525 {
526     CommandObject *proxy_command = GetProxyCommandObject();
527     if (proxy_command)
528         return proxy_command->Execute (args_string, result);
529     result.AppendError ("command is not implemented");
530     result.SetStatus (eReturnStatusFailed);
531     return false;
532 }
533 
534 
535