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    const char *arg0 = input.GetArgumentAtIndex(0);
239    if (cursor_index == 0)
240    {
241        CommandObject::AddNamesMatchingPartialString (m_subcommand_dict,
242                                                      arg0,
243                                                      matches);
244
245        if (matches.GetSize() == 1
246            && matches.GetStringAtIndex(0) != NULL
247            && strcmp (arg0, matches.GetStringAtIndex(0)) == 0)
248        {
249            StringList temp_matches;
250            CommandObject *cmd_obj = GetSubcommandObject (arg0,
251                                                          &temp_matches);
252            if (cmd_obj != NULL)
253            {
254                matches.DeleteStringAtIndex (0);
255                input.Shift();
256                cursor_char_position = 0;
257                input.AppendArgument ("");
258                return cmd_obj->HandleCompletion (input,
259                                                  cursor_index,
260                                                  cursor_char_position,
261                                                  match_start_point,
262                                                  max_return_elements,
263                                                  word_complete,
264                                                  matches);
265            }
266            else
267                return matches.GetSize();
268        }
269        else
270            return matches.GetSize();
271    }
272    else
273    {
274        CommandObject *sub_command_object = GetSubcommandObject (arg0,
275                                                                 &matches);
276        if (sub_command_object == NULL)
277        {
278            return matches.GetSize();
279        }
280        else
281        {
282            // Remove the one match that we got from calling GetSubcommandObject.
283            matches.DeleteStringAtIndex(0);
284            input.Shift();
285            cursor_index--;
286            return sub_command_object->HandleCompletion (input,
287                                                         cursor_index,
288                                                         cursor_char_position,
289                                                         match_start_point,
290                                                         max_return_elements,
291                                                         word_complete,
292                                                         matches);
293        }
294
295    }
296}
297
298const char *
299CommandObjectMultiword::GetRepeatCommand (Args &current_command_args, uint32_t index)
300{
301    index++;
302    if (current_command_args.GetArgumentCount() <= index)
303        return NULL;
304    CommandObject *sub_command_object = GetSubcommandObject (current_command_args.GetArgumentAtIndex(index));
305    if (sub_command_object == NULL)
306        return NULL;
307    return sub_command_object->GetRepeatCommand(current_command_args, index);
308}
309
310
311void
312CommandObjectMultiword::AproposAllSubCommands (const char *prefix,
313                                               const char *search_word,
314                                               StringList &commands_found,
315                                               StringList &commands_help)
316{
317    CommandObject::CommandMap::const_iterator pos;
318
319    for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
320    {
321        const char * command_name = pos->first.c_str();
322        CommandObject *sub_cmd_obj = pos->second.get();
323        StreamString complete_command_name;
324
325        complete_command_name.Printf ("%s %s", prefix, command_name);
326
327        if (sub_cmd_obj->HelpTextContainsWord (search_word))
328        {
329            commands_found.AppendString (complete_command_name.GetData());
330            commands_help.AppendString (sub_cmd_obj->GetHelp());
331        }
332
333        if (sub_cmd_obj->IsMultiwordObject())
334            sub_cmd_obj->AproposAllSubCommands (complete_command_name.GetData(),
335                                                search_word,
336                                                commands_found,
337                                                commands_help);
338    }
339}
340
341
342
343CommandObjectProxy::CommandObjectProxy (CommandInterpreter &interpreter,
344                                        const char *name,
345                                        const char *help,
346                                        const char *syntax,
347                                        uint32_t flags) :
348    CommandObject (interpreter, name, help, syntax, flags)
349{
350}
351
352CommandObjectProxy::~CommandObjectProxy ()
353{
354}
355
356const char *
357CommandObjectProxy::GetHelpLong ()
358{
359    CommandObject *proxy_command = GetProxyCommandObject();
360    if (proxy_command)
361        return proxy_command->GetHelpLong();
362    return NULL;
363}
364
365bool
366CommandObjectProxy::IsRemovable() const
367{
368    const CommandObject *proxy_command = const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
369    if (proxy_command)
370        return proxy_command->IsRemovable();
371    return false;
372}
373
374bool
375CommandObjectProxy::IsMultiwordObject ()
376{
377    CommandObject *proxy_command = GetProxyCommandObject();
378    if (proxy_command)
379        return proxy_command->IsMultiwordObject();
380    return false;
381}
382
383lldb::CommandObjectSP
384CommandObjectProxy::GetSubcommandSP (const char *sub_cmd, StringList *matches)
385{
386    CommandObject *proxy_command = GetProxyCommandObject();
387    if (proxy_command)
388        return proxy_command->GetSubcommandSP(sub_cmd, matches);
389    return lldb::CommandObjectSP();
390}
391
392CommandObject *
393CommandObjectProxy::GetSubcommandObject (const char *sub_cmd, StringList *matches)
394{
395    CommandObject *proxy_command = GetProxyCommandObject();
396    if (proxy_command)
397        return proxy_command->GetSubcommandObject(sub_cmd, matches);
398    return NULL;
399}
400
401void
402CommandObjectProxy::AproposAllSubCommands (const char *prefix,
403                                           const char *search_word,
404                                           StringList &commands_found,
405                                           StringList &commands_help)
406{
407    CommandObject *proxy_command = GetProxyCommandObject();
408    if (proxy_command)
409        return proxy_command->AproposAllSubCommands (prefix,
410                                                     search_word,
411                                                     commands_found,
412                                                     commands_help);
413}
414
415bool
416CommandObjectProxy::LoadSubCommand (const char *cmd_name,
417                                    const lldb::CommandObjectSP& command_sp)
418{
419    CommandObject *proxy_command = GetProxyCommandObject();
420    if (proxy_command)
421        return proxy_command->LoadSubCommand (cmd_name, command_sp);
422    return false;
423}
424
425bool
426CommandObjectProxy::WantsRawCommandString()
427{
428    CommandObject *proxy_command = GetProxyCommandObject();
429    if (proxy_command)
430        return proxy_command->WantsRawCommandString();
431    return false;
432}
433
434bool
435CommandObjectProxy::WantsCompletion()
436{
437    CommandObject *proxy_command = GetProxyCommandObject();
438    if (proxy_command)
439        return proxy_command->WantsCompletion();
440    return false;
441}
442
443
444Options *
445CommandObjectProxy::GetOptions ()
446{
447    CommandObject *proxy_command = GetProxyCommandObject();
448    if (proxy_command)
449        return proxy_command->GetOptions ();
450    return NULL;
451}
452
453
454int
455CommandObjectProxy::HandleCompletion (Args &input,
456                                      int &cursor_index,
457                                      int &cursor_char_position,
458                                      int match_start_point,
459                                      int max_return_elements,
460                                      bool &word_complete,
461                                      StringList &matches)
462{
463    CommandObject *proxy_command = GetProxyCommandObject();
464    if (proxy_command)
465        return proxy_command->HandleCompletion (input,
466                                                cursor_index,
467                                                cursor_char_position,
468                                                match_start_point,
469                                                max_return_elements,
470                                                word_complete,
471                                                matches);
472    matches.Clear();
473    return 0;
474}
475int
476CommandObjectProxy::HandleArgumentCompletion (Args &input,
477                                              int &cursor_index,
478                                              int &cursor_char_position,
479                                              OptionElementVector &opt_element_vector,
480                                              int match_start_point,
481                                              int max_return_elements,
482                                              bool &word_complete,
483                                              StringList &matches)
484{
485    CommandObject *proxy_command = GetProxyCommandObject();
486    if (proxy_command)
487        return proxy_command->HandleArgumentCompletion (input,
488                                                        cursor_index,
489                                                        cursor_char_position,
490                                                        opt_element_vector,
491                                                        match_start_point,
492                                                        max_return_elements,
493                                                        word_complete,
494                                                        matches);
495    matches.Clear();
496    return 0;
497}
498
499const char *
500CommandObjectProxy::GetRepeatCommand (Args &current_command_args,
501                                      uint32_t index)
502{
503    CommandObject *proxy_command = GetProxyCommandObject();
504    if (proxy_command)
505        return proxy_command->GetRepeatCommand (current_command_args, index);
506    return NULL;
507}
508
509bool
510CommandObjectProxy::Execute (const char *args_string,
511                             CommandReturnObject &result)
512{
513    CommandObject *proxy_command = GetProxyCommandObject();
514    if (proxy_command)
515        return proxy_command->Execute (args_string, result);
516    result.AppendError ("command is not implemented");
517    result.SetStatus (eReturnStatusFailed);
518    return false;
519}
520
521
522