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
111 (
112     Args& args,
113     CommandReturnObject &result
114 )
115 {
116     const size_t argc = args.GetArgumentCount();
117     if (argc == 0)
118     {
119         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                 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->ExecuteWithOptions (args, result);
143                 }
144                 else
145                 {
146                     std::string error_msg;
147                     int 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 (int 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(), error_msg.size());
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 (CommandReturnObject &result)
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     Stream &output_stream = result.GetOutputStream();
191     output_stream.PutCString ("The following subcommands are supported:\n\n");
192 
193     CommandMap::iterator pos;
194     uint32_t max_len = m_interpreter.FindLongestCommandWord (m_subcommand_dict);
195 
196     if (max_len)
197         max_len += 4; // Indent the output by 4 spaces.
198 
199     for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
200     {
201         std::string indented_command ("    ");
202         indented_command.append (pos->first);
203         if (pos->second->WantsRawCommandString ())
204         {
205             std::string help_text (pos->second->GetHelp());
206             help_text.append ("  This command takes 'raw' input (no need to quote stuff).");
207             m_interpreter.OutputFormattedHelpText (result.GetOutputStream(),
208                                                    indented_command.c_str(),
209                                                    "--",
210                                                    help_text.c_str(),
211                                                    max_len);
212         }
213         else
214             m_interpreter.OutputFormattedHelpText (result.GetOutputStream(),
215                                                    indented_command.c_str(),
216                                                    "--",
217                                                    pos->second->GetHelp(),
218                                                    max_len);
219     }
220 
221     output_stream.PutCString ("\nFor more help on any particular subcommand, type 'help <command> <subcommand>'.\n");
222 
223     result.SetStatus (eReturnStatusSuccessFinishNoResult);
224 }
225 
226 int
227 CommandObjectMultiword::HandleCompletion
228 (
229     Args &input,
230     int &cursor_index,
231     int &cursor_char_position,
232     int match_start_point,
233     int max_return_elements,
234     bool &word_complete,
235     StringList &matches
236 )
237 {
238     // Any of the command matches will provide a complete word, otherwise the individual
239     // completers will override this.
240     word_complete = true;
241 
242     if (cursor_index == 0)
243     {
244         CommandObject::AddNamesMatchingPartialString (m_subcommand_dict,
245                                                       input.GetArgumentAtIndex(0),
246                                                       matches);
247 
248         if (matches.GetSize() == 1
249             && matches.GetStringAtIndex(0) != NULL
250             && strcmp (input.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0)
251         {
252             StringList temp_matches;
253             CommandObject *cmd_obj = GetSubcommandObject (input.GetArgumentAtIndex(0),
254                                                           &temp_matches);
255             if (cmd_obj != NULL)
256             {
257                 matches.DeleteStringAtIndex (0);
258                 input.Shift();
259                 cursor_char_position = 0;
260                 input.AppendArgument ("");
261                 return cmd_obj->HandleCompletion (input,
262                                                   cursor_index,
263                                                   cursor_char_position,
264                                                   match_start_point,
265                                                   max_return_elements,
266                                                   word_complete,
267                                                   matches);
268             }
269             else
270                 return matches.GetSize();
271         }
272         else
273             return matches.GetSize();
274     }
275     else
276     {
277         CommandObject *sub_command_object = GetSubcommandObject (input.GetArgumentAtIndex(0),
278                                                                  &matches);
279         if (sub_command_object == NULL)
280         {
281             return matches.GetSize();
282         }
283         else
284         {
285             // Remove the one match that we got from calling GetSubcommandObject.
286             matches.DeleteStringAtIndex(0);
287             input.Shift();
288             cursor_index--;
289             return sub_command_object->HandleCompletion (input,
290                                                          cursor_index,
291                                                          cursor_char_position,
292                                                          match_start_point,
293                                                          max_return_elements,
294                                                          word_complete,
295                                                          matches);
296         }
297 
298     }
299 }
300 
301 const char *
302 CommandObjectMultiword::GetRepeatCommand (Args &current_command_args, uint32_t index)
303 {
304     index++;
305     if (current_command_args.GetArgumentCount() <= index)
306         return NULL;
307     CommandObject *sub_command_object = GetSubcommandObject (current_command_args.GetArgumentAtIndex(index));
308     if (sub_command_object == NULL)
309         return NULL;
310     return sub_command_object->GetRepeatCommand(current_command_args, index);
311 }
312 
313