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/lldb-python.h"
11
12#include "lldb/Interpreter/CommandObjectMultiword.h"
13// C Includes
14// C++ Includes
15// Other libraries and framework includes
16// Project includes
17#include "lldb/Core/Debugger.h"
18#include "lldb/Interpreter/CommandInterpreter.h"
19#include "lldb/Interpreter/Options.h"
20#include "lldb/Interpreter/CommandReturnObject.h"
21
22using namespace lldb;
23using namespace lldb_private;
24
25//-------------------------------------------------------------------------
26// CommandObjectMultiword
27//-------------------------------------------------------------------------
28
29CommandObjectMultiword::CommandObjectMultiword
30(
31    CommandInterpreter &interpreter,
32    const char *name,
33    const char *help,
34    const char *syntax,
35    uint32_t flags
36) :
37    CommandObject (interpreter, name, help, syntax, flags),
38    m_can_be_removed(false)
39{
40}
41
42CommandObjectMultiword::~CommandObjectMultiword ()
43{
44}
45
46CommandObjectSP
47CommandObjectMultiword::GetSubcommandSP (const char *sub_cmd, StringList *matches)
48{
49    CommandObjectSP return_cmd_sp;
50    CommandObject::CommandMap::iterator pos;
51
52    if (!m_subcommand_dict.empty())
53    {
54        pos = m_subcommand_dict.find (sub_cmd);
55        if (pos != m_subcommand_dict.end()) {
56            // An exact match; append the sub_cmd to the 'matches' string list.
57            if (matches)
58                matches->AppendString(sub_cmd);
59            return_cmd_sp = pos->second;
60        }
61        else
62        {
63
64            StringList local_matches;
65            if (matches == NULL)
66                matches = &local_matches;
67            int num_matches = CommandObject::AddNamesMatchingPartialString (m_subcommand_dict, sub_cmd, *matches);
68
69            if (num_matches == 1)
70            {
71                // Cleaner, but slightly less efficient would be to call back into this function, since I now
72                // know I have an exact match...
73
74                sub_cmd = matches->GetStringAtIndex(0);
75                pos = m_subcommand_dict.find(sub_cmd);
76                if (pos != m_subcommand_dict.end())
77                    return_cmd_sp = pos->second;
78            }
79        }
80    }
81    return return_cmd_sp;
82}
83
84CommandObject *
85CommandObjectMultiword::GetSubcommandObject (const char *sub_cmd, StringList *matches)
86{
87    return GetSubcommandSP(sub_cmd, matches).get();
88}
89
90bool
91CommandObjectMultiword::LoadSubCommand
92(
93    const char *name,
94    const CommandObjectSP& cmd_obj
95)
96{
97    CommandMap::iterator pos;
98    bool success = true;
99
100    pos = m_subcommand_dict.find(name);
101    if (pos == m_subcommand_dict.end())
102    {
103        m_subcommand_dict[name] = cmd_obj;
104    }
105    else
106        success = false;
107
108    return success;
109}
110
111bool
112CommandObjectMultiword::Execute(const char *args_string, CommandReturnObject &result)
113{
114    Args args (args_string);
115    const size_t argc = args.GetArgumentCount();
116    if (argc == 0)
117    {
118        this->CommandObject::GenerateHelpText (result);
119    }
120    else
121    {
122        const char *sub_command = args.GetArgumentAtIndex (0);
123
124        if (sub_command)
125        {
126            if (::strcasecmp (sub_command, "help") == 0)
127            {
128                this->CommandObject::GenerateHelpText (result);
129            }
130            else if (!m_subcommand_dict.empty())
131            {
132                StringList matches;
133                CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
134                if (sub_cmd_obj != NULL)
135                {
136                    // Now call CommandObject::Execute to process and options in 'rest_of_line'.  From there
137                    // the command-specific version of Execute will be called, with the processed arguments.
138
139                    args.Shift();
140
141                    sub_cmd_obj->Execute (args_string, result);
142                }
143                else
144                {
145                    std::string error_msg;
146                    const size_t num_subcmd_matches = matches.GetSize();
147                    if (num_subcmd_matches > 0)
148                        error_msg.assign ("ambiguous command ");
149                    else
150                        error_msg.assign ("invalid command ");
151
152                    error_msg.append ("'");
153                    error_msg.append (GetCommandName());
154                    error_msg.append (" ");
155                    error_msg.append (sub_command);
156                    error_msg.append ("'");
157
158                    if (num_subcmd_matches > 0)
159                    {
160                        error_msg.append (" Possible completions:");
161                        for (size_t i = 0; i < num_subcmd_matches; i++)
162                        {
163                            error_msg.append ("\n\t");
164                            error_msg.append (matches.GetStringAtIndex (i));
165                        }
166                    }
167                    error_msg.append ("\n");
168                    result.AppendRawError (error_msg.c_str());
169                    result.SetStatus (eReturnStatusFailed);
170                }
171            }
172            else
173            {
174                result.AppendErrorWithFormat ("'%s' does not have any subcommands.\n", GetCommandName());
175                result.SetStatus (eReturnStatusFailed);
176            }
177        }
178    }
179
180    return result.Succeeded();
181}
182
183void
184CommandObjectMultiword::GenerateHelpText (Stream &output_stream)
185{
186    // First time through here, generate the help text for the object and
187    // push it to the return result object as well
188
189    output_stream.PutCString ("The following subcommands are supported:\n\n");
190
191    CommandMap::iterator pos;
192    uint32_t max_len = m_interpreter.FindLongestCommandWord (m_subcommand_dict);
193
194    if (max_len)
195        max_len += 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        if (pos->second->WantsRawCommandString ())
202        {
203            std::string help_text (pos->second->GetHelp());
204            help_text.append ("  This command takes 'raw' input (no need to quote stuff).");
205            m_interpreter.OutputFormattedHelpText (output_stream,
206                                                   indented_command.c_str(),
207                                                   "--",
208                                                   help_text.c_str(),
209                                                   max_len);
210        }
211        else
212            m_interpreter.OutputFormattedHelpText (output_stream,
213                                                   indented_command.c_str(),
214                                                   "--",
215                                                   pos->second->GetHelp(),
216                                                   max_len);
217    }
218
219    output_stream.PutCString ("\nFor more help on any particular subcommand, type 'help <command> <subcommand>'.\n");
220}
221
222int
223CommandObjectMultiword::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
297const char *
298CommandObjectMultiword::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
310void
311CommandObjectMultiword::AproposAllSubCommands (const char *prefix,
312                                               const char *search_word,
313                                               StringList &commands_found,
314                                               StringList &commands_help)
315{
316    CommandObject::CommandMap::const_iterator pos;
317
318    for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
319    {
320        const char * command_name = pos->first.c_str();
321        CommandObject *sub_cmd_obj = pos->second.get();
322        StreamString complete_command_name;
323
324        complete_command_name.Printf ("%s %s", prefix, command_name);
325
326        if (sub_cmd_obj->HelpTextContainsWord (search_word))
327        {
328            commands_found.AppendString (complete_command_name.GetData());
329            commands_help.AppendString (sub_cmd_obj->GetHelp());
330        }
331
332        if (sub_cmd_obj->IsMultiwordObject())
333            sub_cmd_obj->AproposAllSubCommands (complete_command_name.GetData(),
334                                                search_word,
335                                                commands_found,
336                                                commands_help);
337    }
338}
339
340
341
342CommandObjectProxy::CommandObjectProxy (CommandInterpreter &interpreter,
343                                        const char *name,
344                                        const char *help,
345                                        const char *syntax,
346                                        uint32_t flags) :
347    CommandObject (interpreter, name, help, syntax, flags)
348{
349}
350
351CommandObjectProxy::~CommandObjectProxy ()
352{
353}
354
355const char *
356CommandObjectProxy::GetHelpLong ()
357{
358    CommandObject *proxy_command = GetProxyCommandObject();
359    if (proxy_command)
360        return proxy_command->GetHelpLong();
361    return NULL;
362}
363
364bool
365CommandObjectProxy::IsRemovable() const
366{
367    const CommandObject *proxy_command = const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
368    if (proxy_command)
369        return proxy_command->IsRemovable();
370    return false;
371}
372
373bool
374CommandObjectProxy::IsMultiwordObject ()
375{
376    CommandObject *proxy_command = GetProxyCommandObject();
377    if (proxy_command)
378        return proxy_command->IsMultiwordObject();
379    return false;
380}
381
382lldb::CommandObjectSP
383CommandObjectProxy::GetSubcommandSP (const char *sub_cmd, StringList *matches)
384{
385    CommandObject *proxy_command = GetProxyCommandObject();
386    if (proxy_command)
387        return proxy_command->GetSubcommandSP(sub_cmd, matches);
388    return lldb::CommandObjectSP();
389}
390
391CommandObject *
392CommandObjectProxy::GetSubcommandObject (const char *sub_cmd, StringList *matches)
393{
394    CommandObject *proxy_command = GetProxyCommandObject();
395    if (proxy_command)
396        return proxy_command->GetSubcommandObject(sub_cmd, matches);
397    return NULL;
398}
399
400void
401CommandObjectProxy::AproposAllSubCommands (const char *prefix,
402                                           const char *search_word,
403                                           StringList &commands_found,
404                                           StringList &commands_help)
405{
406    CommandObject *proxy_command = GetProxyCommandObject();
407    if (proxy_command)
408        return proxy_command->AproposAllSubCommands (prefix,
409                                                     search_word,
410                                                     commands_found,
411                                                     commands_help);
412}
413
414bool
415CommandObjectProxy::LoadSubCommand (const char *cmd_name,
416                                    const lldb::CommandObjectSP& command_sp)
417{
418    CommandObject *proxy_command = GetProxyCommandObject();
419    if (proxy_command)
420        return proxy_command->LoadSubCommand (cmd_name, command_sp);
421    return false;
422}
423
424bool
425CommandObjectProxy::WantsRawCommandString()
426{
427    CommandObject *proxy_command = GetProxyCommandObject();
428    if (proxy_command)
429        return proxy_command->WantsRawCommandString();
430    return false;
431}
432
433bool
434CommandObjectProxy::WantsCompletion()
435{
436    CommandObject *proxy_command = GetProxyCommandObject();
437    if (proxy_command)
438        return proxy_command->WantsCompletion();
439    return false;
440}
441
442
443Options *
444CommandObjectProxy::GetOptions ()
445{
446    CommandObject *proxy_command = GetProxyCommandObject();
447    if (proxy_command)
448        return proxy_command->GetOptions ();
449    return NULL;
450}
451
452
453int
454CommandObjectProxy::HandleCompletion (Args &input,
455                                      int &cursor_index,
456                                      int &cursor_char_position,
457                                      int match_start_point,
458                                      int max_return_elements,
459                                      bool &word_complete,
460                                      StringList &matches)
461{
462    CommandObject *proxy_command = GetProxyCommandObject();
463    if (proxy_command)
464        return proxy_command->HandleCompletion (input,
465                                                cursor_index,
466                                                cursor_char_position,
467                                                match_start_point,
468                                                max_return_elements,
469                                                word_complete,
470                                                matches);
471    matches.Clear();
472    return 0;
473}
474int
475CommandObjectProxy::HandleArgumentCompletion (Args &input,
476                                              int &cursor_index,
477                                              int &cursor_char_position,
478                                              OptionElementVector &opt_element_vector,
479                                              int match_start_point,
480                                              int max_return_elements,
481                                              bool &word_complete,
482                                              StringList &matches)
483{
484    CommandObject *proxy_command = GetProxyCommandObject();
485    if (proxy_command)
486        return proxy_command->HandleArgumentCompletion (input,
487                                                        cursor_index,
488                                                        cursor_char_position,
489                                                        opt_element_vector,
490                                                        match_start_point,
491                                                        max_return_elements,
492                                                        word_complete,
493                                                        matches);
494    matches.Clear();
495    return 0;
496}
497
498const char *
499CommandObjectProxy::GetRepeatCommand (Args &current_command_args,
500                                      uint32_t index)
501{
502    CommandObject *proxy_command = GetProxyCommandObject();
503    if (proxy_command)
504        return proxy_command->GetRepeatCommand (current_command_args, index);
505    return NULL;
506}
507
508bool
509CommandObjectProxy::Execute (const char *args_string,
510                             CommandReturnObject &result)
511{
512    CommandObject *proxy_command = GetProxyCommandObject();
513    if (proxy_command)
514        return proxy_command->Execute (args_string, result);
515    result.AppendError ("command is not implemented");
516    result.SetStatus (eReturnStatusFailed);
517    return false;
518}
519
520
521