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
CommandObjectMultiword(CommandInterpreter & interpreter,const char * name,const char * help,const char * syntax,uint32_t flags)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
~CommandObjectMultiword()40 CommandObjectMultiword::~CommandObjectMultiword ()
41 {
42 }
43
44 CommandObjectSP
GetSubcommandSP(const char * sub_cmd,StringList * matches)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 *
GetSubcommandObject(const char * sub_cmd,StringList * matches)83 CommandObjectMultiword::GetSubcommandObject (const char *sub_cmd, StringList *matches)
84 {
85 return GetSubcommandSP(sub_cmd, matches).get();
86 }
87
88 bool
LoadSubCommand(const char * name,const CommandObjectSP & cmd_obj)89 CommandObjectMultiword::LoadSubCommand
90 (
91 const char *name,
92 const CommandObjectSP& cmd_obj
93 )
94 {
95 CommandMap::iterator pos;
96 bool success = true;
97
98 pos = m_subcommand_dict.find(name);
99 if (pos == m_subcommand_dict.end())
100 {
101 m_subcommand_dict[name] = cmd_obj;
102 }
103 else
104 success = false;
105
106 return success;
107 }
108
109 bool
Execute(const char * args_string,CommandReturnObject & result)110 CommandObjectMultiword::Execute(const char *args_string, CommandReturnObject &result)
111 {
112 Args args (args_string);
113 const size_t argc = args.GetArgumentCount();
114 if (argc == 0)
115 {
116 this->CommandObject::GenerateHelpText (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 this->CommandObject::GenerateHelpText (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->Execute (args_string, result);
140 }
141 else
142 {
143 std::string error_msg;
144 const size_t 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 (size_t 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());
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
GenerateHelpText(Stream & output_stream)182 CommandObjectMultiword::GenerateHelpText (Stream &output_stream)
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 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 (output_stream,
204 indented_command.c_str(),
205 "--",
206 help_text.c_str(),
207 max_len);
208 }
209 else
210 m_interpreter.OutputFormattedHelpText (output_stream,
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
220 int
HandleCompletion(Args & input,int & cursor_index,int & cursor_char_position,int match_start_point,int max_return_elements,bool & word_complete,StringList & matches)221 CommandObjectMultiword::HandleCompletion
222 (
223 Args &input,
224 int &cursor_index,
225 int &cursor_char_position,
226 int match_start_point,
227 int max_return_elements,
228 bool &word_complete,
229 StringList &matches
230 )
231 {
232 // Any of the command matches will provide a complete word, otherwise the individual
233 // completers will override this.
234 word_complete = true;
235
236 const char *arg0 = input.GetArgumentAtIndex(0);
237 if (cursor_index == 0)
238 {
239 CommandObject::AddNamesMatchingPartialString (m_subcommand_dict,
240 arg0,
241 matches);
242
243 if (matches.GetSize() == 1
244 && matches.GetStringAtIndex(0) != NULL
245 && strcmp (arg0, matches.GetStringAtIndex(0)) == 0)
246 {
247 StringList temp_matches;
248 CommandObject *cmd_obj = GetSubcommandObject (arg0,
249 &temp_matches);
250 if (cmd_obj != NULL)
251 {
252 if (input.GetArgumentCount() == 1)
253 {
254 word_complete = true;
255 }
256 else
257 {
258 matches.DeleteStringAtIndex (0);
259 input.Shift();
260 cursor_char_position = 0;
261 input.AppendArgument ("");
262 return cmd_obj->HandleCompletion (input,
263 cursor_index,
264 cursor_char_position,
265 match_start_point,
266 max_return_elements,
267 word_complete,
268 matches);
269 }
270 }
271 }
272 return matches.GetSize();
273 }
274 else
275 {
276 CommandObject *sub_command_object = GetSubcommandObject (arg0,
277 &matches);
278 if (sub_command_object == NULL)
279 {
280 return matches.GetSize();
281 }
282 else
283 {
284 // Remove the one match that we got from calling GetSubcommandObject.
285 matches.DeleteStringAtIndex(0);
286 input.Shift();
287 cursor_index--;
288 return sub_command_object->HandleCompletion (input,
289 cursor_index,
290 cursor_char_position,
291 match_start_point,
292 max_return_elements,
293 word_complete,
294 matches);
295 }
296
297 }
298 }
299
300 const char *
GetRepeatCommand(Args & current_command_args,uint32_t index)301 CommandObjectMultiword::GetRepeatCommand (Args ¤t_command_args, uint32_t index)
302 {
303 index++;
304 if (current_command_args.GetArgumentCount() <= index)
305 return NULL;
306 CommandObject *sub_command_object = GetSubcommandObject (current_command_args.GetArgumentAtIndex(index));
307 if (sub_command_object == NULL)
308 return NULL;
309 return sub_command_object->GetRepeatCommand(current_command_args, index);
310 }
311
312
313 void
AproposAllSubCommands(const char * prefix,const char * search_word,StringList & commands_found,StringList & commands_help)314 CommandObjectMultiword::AproposAllSubCommands (const char *prefix,
315 const char *search_word,
316 StringList &commands_found,
317 StringList &commands_help)
318 {
319 CommandObject::CommandMap::const_iterator pos;
320
321 for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
322 {
323 const char * command_name = pos->first.c_str();
324 CommandObject *sub_cmd_obj = pos->second.get();
325 StreamString complete_command_name;
326
327 complete_command_name.Printf ("%s %s", prefix, command_name);
328
329 if (sub_cmd_obj->HelpTextContainsWord (search_word))
330 {
331 commands_found.AppendString (complete_command_name.GetData());
332 commands_help.AppendString (sub_cmd_obj->GetHelp());
333 }
334
335 if (sub_cmd_obj->IsMultiwordObject())
336 sub_cmd_obj->AproposAllSubCommands (complete_command_name.GetData(),
337 search_word,
338 commands_found,
339 commands_help);
340 }
341 }
342
343
344
CommandObjectProxy(CommandInterpreter & interpreter,const char * name,const char * help,const char * syntax,uint32_t flags)345 CommandObjectProxy::CommandObjectProxy (CommandInterpreter &interpreter,
346 const char *name,
347 const char *help,
348 const char *syntax,
349 uint32_t flags) :
350 CommandObject (interpreter, name, help, syntax, flags)
351 {
352 }
353
~CommandObjectProxy()354 CommandObjectProxy::~CommandObjectProxy ()
355 {
356 }
357
358 const char *
GetHelpLong()359 CommandObjectProxy::GetHelpLong ()
360 {
361 CommandObject *proxy_command = GetProxyCommandObject();
362 if (proxy_command)
363 return proxy_command->GetHelpLong();
364 return NULL;
365 }
366
367 bool
IsRemovable() const368 CommandObjectProxy::IsRemovable() const
369 {
370 const CommandObject *proxy_command = const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
371 if (proxy_command)
372 return proxy_command->IsRemovable();
373 return false;
374 }
375
376 bool
IsMultiwordObject()377 CommandObjectProxy::IsMultiwordObject ()
378 {
379 CommandObject *proxy_command = GetProxyCommandObject();
380 if (proxy_command)
381 return proxy_command->IsMultiwordObject();
382 return false;
383 }
384
385 lldb::CommandObjectSP
GetSubcommandSP(const char * sub_cmd,StringList * matches)386 CommandObjectProxy::GetSubcommandSP (const char *sub_cmd, StringList *matches)
387 {
388 CommandObject *proxy_command = GetProxyCommandObject();
389 if (proxy_command)
390 return proxy_command->GetSubcommandSP(sub_cmd, matches);
391 return lldb::CommandObjectSP();
392 }
393
394 CommandObject *
GetSubcommandObject(const char * sub_cmd,StringList * matches)395 CommandObjectProxy::GetSubcommandObject (const char *sub_cmd, StringList *matches)
396 {
397 CommandObject *proxy_command = GetProxyCommandObject();
398 if (proxy_command)
399 return proxy_command->GetSubcommandObject(sub_cmd, matches);
400 return NULL;
401 }
402
403 void
AproposAllSubCommands(const char * prefix,const char * search_word,StringList & commands_found,StringList & commands_help)404 CommandObjectProxy::AproposAllSubCommands (const char *prefix,
405 const char *search_word,
406 StringList &commands_found,
407 StringList &commands_help)
408 {
409 CommandObject *proxy_command = GetProxyCommandObject();
410 if (proxy_command)
411 return proxy_command->AproposAllSubCommands (prefix,
412 search_word,
413 commands_found,
414 commands_help);
415 }
416
417 bool
LoadSubCommand(const char * cmd_name,const lldb::CommandObjectSP & command_sp)418 CommandObjectProxy::LoadSubCommand (const char *cmd_name,
419 const lldb::CommandObjectSP& command_sp)
420 {
421 CommandObject *proxy_command = GetProxyCommandObject();
422 if (proxy_command)
423 return proxy_command->LoadSubCommand (cmd_name, command_sp);
424 return false;
425 }
426
427 bool
WantsRawCommandString()428 CommandObjectProxy::WantsRawCommandString()
429 {
430 CommandObject *proxy_command = GetProxyCommandObject();
431 if (proxy_command)
432 return proxy_command->WantsRawCommandString();
433 return false;
434 }
435
436 bool
WantsCompletion()437 CommandObjectProxy::WantsCompletion()
438 {
439 CommandObject *proxy_command = GetProxyCommandObject();
440 if (proxy_command)
441 return proxy_command->WantsCompletion();
442 return false;
443 }
444
445
446 Options *
GetOptions()447 CommandObjectProxy::GetOptions ()
448 {
449 CommandObject *proxy_command = GetProxyCommandObject();
450 if (proxy_command)
451 return proxy_command->GetOptions ();
452 return NULL;
453 }
454
455
456 int
HandleCompletion(Args & input,int & cursor_index,int & cursor_char_position,int match_start_point,int max_return_elements,bool & word_complete,StringList & matches)457 CommandObjectProxy::HandleCompletion (Args &input,
458 int &cursor_index,
459 int &cursor_char_position,
460 int match_start_point,
461 int max_return_elements,
462 bool &word_complete,
463 StringList &matches)
464 {
465 CommandObject *proxy_command = GetProxyCommandObject();
466 if (proxy_command)
467 return proxy_command->HandleCompletion (input,
468 cursor_index,
469 cursor_char_position,
470 match_start_point,
471 max_return_elements,
472 word_complete,
473 matches);
474 matches.Clear();
475 return 0;
476 }
477 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)478 CommandObjectProxy::HandleArgumentCompletion (Args &input,
479 int &cursor_index,
480 int &cursor_char_position,
481 OptionElementVector &opt_element_vector,
482 int match_start_point,
483 int max_return_elements,
484 bool &word_complete,
485 StringList &matches)
486 {
487 CommandObject *proxy_command = GetProxyCommandObject();
488 if (proxy_command)
489 return proxy_command->HandleArgumentCompletion (input,
490 cursor_index,
491 cursor_char_position,
492 opt_element_vector,
493 match_start_point,
494 max_return_elements,
495 word_complete,
496 matches);
497 matches.Clear();
498 return 0;
499 }
500
501 const char *
GetRepeatCommand(Args & current_command_args,uint32_t index)502 CommandObjectProxy::GetRepeatCommand (Args ¤t_command_args,
503 uint32_t index)
504 {
505 CommandObject *proxy_command = GetProxyCommandObject();
506 if (proxy_command)
507 return proxy_command->GetRepeatCommand (current_command_args, index);
508 return NULL;
509 }
510
511 bool
Execute(const char * args_string,CommandReturnObject & result)512 CommandObjectProxy::Execute (const char *args_string,
513 CommandReturnObject &result)
514 {
515 CommandObject *proxy_command = GetProxyCommandObject();
516 if (proxy_command)
517 return proxy_command->Execute (args_string, result);
518 result.AppendError ("command is not implemented");
519 result.SetStatus (eReturnStatusFailed);
520 return false;
521 }
522
523
524