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     const char *name,
30     const char *help,
31     const char *syntax,
32     uint32_t flags
33 ) :
34     CommandObject (name, help, syntax, flags)
35 {
36 }
37 
38 CommandObjectMultiword::~CommandObjectMultiword ()
39 {
40 }
41 
42 CommandObjectSP
43 CommandObjectMultiword::GetSubcommandSP (const char *sub_cmd, StringList *matches)
44 {
45     CommandObjectSP return_cmd_sp;
46     CommandObject::CommandMap::iterator pos;
47 
48     if (!m_subcommand_dict.empty())
49     {
50         pos = m_subcommand_dict.find (sub_cmd);
51         if (pos != m_subcommand_dict.end())
52             return_cmd_sp = pos->second;
53         else
54         {
55 
56             StringList local_matches;
57             if (matches == NULL)
58                 matches = &local_matches;
59             int num_matches = CommandObject::AddNamesMatchingPartialString (m_subcommand_dict, sub_cmd, *matches);
60 
61             if (num_matches == 1)
62             {
63                 // Cleaner, but slightly less efficient would be to call back into this function, since I now
64                 // know I have an exact match...
65 
66                 sub_cmd = matches->GetStringAtIndex(0);
67                 pos = m_subcommand_dict.find(sub_cmd);
68                 if (pos != m_subcommand_dict.end())
69                     return_cmd_sp = pos->second;
70             }
71         }
72     }
73     return return_cmd_sp;
74 }
75 
76 CommandObject *
77 CommandObjectMultiword::GetSubcommandObject (const char *sub_cmd, StringList *matches)
78 {
79     return GetSubcommandSP(sub_cmd, matches).get();
80 }
81 
82 bool
83 CommandObjectMultiword::LoadSubCommand
84 (
85     CommandInterpreter &interpreter,
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         interpreter.CrossRegisterCommand (name, GetCommandName());
98     }
99     else
100         success = false;
101 
102     return success;
103 }
104 
105 bool
106 CommandObjectMultiword::Execute
107 (
108     CommandInterpreter &interpreter,
109     Args& args,
110     CommandReturnObject &result
111 )
112 {
113     const size_t argc = args.GetArgumentCount();
114     if (argc == 0)
115     {
116         GenerateHelpText (interpreter, result);
117     }
118     else
119     {
120         const char *sub_command = args.GetArgumentAtIndex (0);
121 
122         if (sub_command)
123         {
124             if (::strcasecmp (sub_command, "help") == 0)
125             {
126                 GenerateHelpText (interpreter, result);
127             }
128             else if (!m_subcommand_dict.empty())
129             {
130                 StringList matches;
131                 CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
132                 if (sub_cmd_obj != NULL)
133                 {
134                     // Now call CommandObject::Execute to process and options in 'rest_of_line'.  From there
135                     // the command-specific version of Execute will be called, with the processed arguments.
136 
137                     args.Shift();
138 
139                     sub_cmd_obj->ExecuteWithOptions (interpreter, args, result);
140                 }
141                 else
142                 {
143                     std::string error_msg;
144                     int num_subcmd_matches = matches.GetSize();
145                     if (num_subcmd_matches > 0)
146                         error_msg.assign ("ambiguous command ");
147                     else
148                         error_msg.assign ("invalid command ");
149 
150                     error_msg.append ("'");
151                     error_msg.append (GetCommandName());
152                     error_msg.append (" ");
153                     error_msg.append (sub_command);
154                     error_msg.append ("'");
155 
156                     if (num_subcmd_matches > 0)
157                     {
158                         error_msg.append (" Possible completions:");
159                         for (int i = 0; i < num_subcmd_matches; i++)
160                         {
161                             error_msg.append ("\n\t");
162                             error_msg.append (matches.GetStringAtIndex (i));
163                         }
164                     }
165                     error_msg.append ("\n");
166                     result.AppendRawError (error_msg.c_str(), error_msg.size());
167                     result.SetStatus (eReturnStatusFailed);
168                 }
169             }
170             else
171             {
172                 result.AppendErrorWithFormat ("'%s' does not have any subcommands.\n", GetCommandName());
173                 result.SetStatus (eReturnStatusFailed);
174             }
175         }
176     }
177 
178     return result.Succeeded();
179 }
180 
181 void
182 CommandObjectMultiword::GenerateHelpText (CommandInterpreter &interpreter, CommandReturnObject &result)
183 {
184     // First time through here, generate the help text for the object and
185     // push it to the return result object as well
186 
187     StreamString &output_stream = result.GetOutputStream();
188     output_stream.PutCString ("The following subcommands are supported:\n\n");
189 
190     CommandMap::iterator pos;
191     std::string longest_word = interpreter.FindLongestCommandWord (m_subcommand_dict);
192     uint32_t max_len = 0;
193 
194     if (! longest_word.empty())
195         max_len = strlen (longest_word.c_str()) + 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         interpreter.OutputFormattedHelpText (result.GetOutputStream(),
202                                              indented_command.c_str(),
203                                              "--",
204                                              pos->second->GetHelp(),
205                                              max_len);
206     }
207 
208     output_stream.PutCString ("\nFor more help on any particular subcommand, type 'help <command> <subcommand>'.\n");
209 
210     result.SetStatus (eReturnStatusSuccessFinishNoResult);
211 }
212 
213 int
214 CommandObjectMultiword::HandleCompletion
215 (
216     CommandInterpreter &interpreter,
217     Args &input,
218     int &cursor_index,
219     int &cursor_char_position,
220     int match_start_point,
221     int max_return_elements,
222     bool &word_complete,
223     StringList &matches
224 )
225 {
226     // Any of the command matches will provide a complete word, otherwise the individual
227     // completers will override this.
228     word_complete = true;
229 
230     if (cursor_index == 0)
231     {
232         CommandObject::AddNamesMatchingPartialString (m_subcommand_dict,
233                                                       input.GetArgumentAtIndex(0),
234                                                       matches);
235 
236         if (matches.GetSize() == 1
237             && matches.GetStringAtIndex(0) != NULL
238             && strcmp (input.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0)
239         {
240             StringList temp_matches;
241             CommandObject *cmd_obj = GetSubcommandObject (input.GetArgumentAtIndex(0),
242                                                           &temp_matches);
243             if (cmd_obj != NULL)
244             {
245                 matches.DeleteStringAtIndex (0);
246                 input.Shift();
247                 cursor_char_position = 0;
248                 input.AppendArgument ("");
249                 return cmd_obj->HandleCompletion (interpreter,
250                                                   input, cursor_index,
251                                                   cursor_char_position,
252                                                   match_start_point,
253                                                   max_return_elements,
254                                                   word_complete,
255                                                   matches);
256             }
257             else
258                 return matches.GetSize();
259         }
260         else
261             return matches.GetSize();
262     }
263     else
264     {
265         CommandObject *sub_command_object = GetSubcommandObject (input.GetArgumentAtIndex(0),
266                                                                  &matches);
267         if (sub_command_object == NULL)
268         {
269             return matches.GetSize();
270         }
271         else
272         {
273             // Remove the one match that we got from calling GetSubcommandObject.
274             matches.DeleteStringAtIndex(0);
275             input.Shift();
276             cursor_index--;
277             return sub_command_object->HandleCompletion (interpreter,
278                                                          input,
279                                                          cursor_index,
280                                                          cursor_char_position,
281                                                          match_start_point,
282                                                          max_return_elements,
283                                                          word_complete,
284                                                          matches);
285         }
286 
287     }
288 }
289 
290