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             return_cmd_sp = pos->second;
54         else
55         {
56 
57             StringList local_matches;
58             if (matches == NULL)
59                 matches = &local_matches;
60             int num_matches = CommandObject::AddNamesMatchingPartialString (m_subcommand_dict, sub_cmd, *matches);
61 
62             if (num_matches == 1)
63             {
64                 // Cleaner, but slightly less efficient would be to call back into this function, since I now
65                 // know I have an exact match...
66 
67                 sub_cmd = matches->GetStringAtIndex(0);
68                 pos = m_subcommand_dict.find(sub_cmd);
69                 if (pos != m_subcommand_dict.end())
70                     return_cmd_sp = pos->second;
71             }
72         }
73     }
74     return return_cmd_sp;
75 }
76 
77 CommandObject *
78 CommandObjectMultiword::GetSubcommandObject (const char *sub_cmd, StringList *matches)
79 {
80     return GetSubcommandSP(sub_cmd, matches).get();
81 }
82 
83 bool
84 CommandObjectMultiword::LoadSubCommand
85 (
86     const char *name,
87     const CommandObjectSP& cmd_obj
88 )
89 {
90     CommandMap::iterator pos;
91     bool success = true;
92 
93     pos = m_subcommand_dict.find(name);
94     if (pos == m_subcommand_dict.end())
95     {
96         m_subcommand_dict[name] = cmd_obj;
97         m_interpreter.CrossRegisterCommand (name, GetCommandName());
98     }
99     else
100         success = false;
101 
102     return success;
103 }
104 
105 bool
106 CommandObjectMultiword::Execute
107 (
108     Args& args,
109     CommandReturnObject &result
110 )
111 {
112     const size_t argc = args.GetArgumentCount();
113     if (argc == 0)
114     {
115         GenerateHelpText (result);
116     }
117     else
118     {
119         const char *sub_command = args.GetArgumentAtIndex (0);
120 
121         if (sub_command)
122         {
123             if (::strcasecmp (sub_command, "help") == 0)
124             {
125                 GenerateHelpText (result);
126             }
127             else if (!m_subcommand_dict.empty())
128             {
129                 StringList matches;
130                 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
131                 if (sub_cmd_obj != NULL)
132                 {
133                     // Now call CommandObject::Execute to process and options in 'rest_of_line'.  From there
134                     // the command-specific version of Execute will be called, with the processed arguments.
135 
136                     args.Shift();
137 
138                     sub_cmd_obj->ExecuteWithOptions (args, result);
139                 }
140                 else
141                 {
142                     std::string error_msg;
143                     int num_subcmd_matches = matches.GetSize();
144                     if (num_subcmd_matches > 0)
145                         error_msg.assign ("ambiguous command ");
146                     else
147                         error_msg.assign ("invalid command ");
148 
149                     error_msg.append ("'");
150                     error_msg.append (GetCommandName());
151                     error_msg.append (" ");
152                     error_msg.append (sub_command);
153                     error_msg.append ("'");
154 
155                     if (num_subcmd_matches > 0)
156                     {
157                         error_msg.append (" Possible completions:");
158                         for (int i = 0; i < num_subcmd_matches; i++)
159                         {
160                             error_msg.append ("\n\t");
161                             error_msg.append (matches.GetStringAtIndex (i));
162                         }
163                     }
164                     error_msg.append ("\n");
165                     result.AppendRawError (error_msg.c_str(), error_msg.size());
166                     result.SetStatus (eReturnStatusFailed);
167                 }
168             }
169             else
170             {
171                 result.AppendErrorWithFormat ("'%s' does not have any subcommands.\n", GetCommandName());
172                 result.SetStatus (eReturnStatusFailed);
173             }
174         }
175     }
176 
177     return result.Succeeded();
178 }
179 
180 void
181 CommandObjectMultiword::GenerateHelpText (CommandReturnObject &result)
182 {
183     // First time through here, generate the help text for the object and
184     // push it to the return result object as well
185 
186     StreamString &output_stream = result.GetOutputStream();
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 (result.GetOutputStream(),
204                                                    indented_command.c_str(),
205                                                    "--",
206                                                    help_text.c_str(),
207                                                    max_len);
208         }
209         else
210             m_interpreter.OutputFormattedHelpText (result.GetOutputStream(),
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     result.SetStatus (eReturnStatusSuccessFinishNoResult);
220 }
221 
222 int
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 *
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