CommandAlias.cpp revision 309124
1//===-- CommandAlias.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/CommandAlias.h"
11
12#include "llvm/Support/ErrorHandling.h"
13
14#include "lldb/Core/StreamString.h"
15#include "lldb/Interpreter/CommandObject.h"
16#include "lldb/Interpreter/CommandReturnObject.h"
17#include "lldb/Interpreter/Options.h"
18
19using namespace lldb;
20using namespace lldb_private;
21
22static bool
23ProcessAliasOptionsArgs (lldb::CommandObjectSP &cmd_obj_sp,
24                         const char *options_args,
25                         OptionArgVectorSP &option_arg_vector_sp)
26{
27    bool success = true;
28    OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
29
30    if (!options_args || (strlen (options_args) < 1))
31        return true;
32
33    std::string options_string (options_args);
34    Args args (options_args);
35    CommandReturnObject result;
36    // Check to see if the command being aliased can take any command options.
37    Options *options = cmd_obj_sp->GetOptions ();
38    if (options)
39    {
40        // See if any options were specified as part of the alias;  if so, handle them appropriately.
41        options->NotifyOptionParsingStarting ();
42        args.Unshift ("dummy_arg");
43        args.ParseAliasOptions (*options, result, option_arg_vector, options_string);
44        args.Shift ();
45        if (result.Succeeded())
46            options->VerifyPartialOptions (result);
47        if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted)
48        {
49            result.AppendError ("Unable to create requested alias.\n");
50            return false;
51        }
52    }
53
54    if (!options_string.empty())
55    {
56        if (cmd_obj_sp->WantsRawCommandString ())
57            option_arg_vector->push_back (OptionArgPair ("<argument>",
58                                                         OptionArgValue (-1,
59                                                                         options_string)));
60        else
61        {
62            const size_t argc = args.GetArgumentCount();
63            for (size_t i = 0; i < argc; ++i)
64                if (strcmp (args.GetArgumentAtIndex (i), "") != 0)
65                    option_arg_vector->push_back
66                    (OptionArgPair ("<argument>",
67                                    OptionArgValue (-1,
68                                                    std::string (args.GetArgumentAtIndex (i)))));
69        }
70    }
71
72    return success;
73}
74
75CommandAlias::CommandAlias (CommandInterpreter &interpreter,
76                            lldb::CommandObjectSP cmd_sp,
77                            const char *options_args,
78                            const char *name,
79                            const char *help,
80                            const char *syntax,
81                            uint32_t flags) :
82    CommandObject(interpreter,
83                  name,
84                  help,
85                  syntax,
86                  flags),
87m_underlying_command_sp(),
88m_option_string(options_args ? options_args : ""),
89m_option_args_sp(new OptionArgVector),
90m_is_dashdash_alias(eLazyBoolCalculate),
91m_did_set_help(false),
92m_did_set_help_long(false)
93{
94    if (ProcessAliasOptionsArgs(cmd_sp, options_args, m_option_args_sp))
95    {
96        m_underlying_command_sp = cmd_sp;
97        for (int i = 0;
98             auto cmd_entry = m_underlying_command_sp->GetArgumentEntryAtIndex(i);
99             i++)
100        {
101            m_arguments.push_back(*cmd_entry);
102        }
103        if (!help || !help[0])
104        {
105            StreamString sstr;
106            StreamString translation_and_help;
107            GetAliasExpansion(sstr);
108
109            translation_and_help.Printf ("(%s)  %s", sstr.GetData(), GetUnderlyingCommand()->GetHelp());
110            SetHelp(translation_and_help.GetData());
111        }
112    }
113}
114
115bool
116CommandAlias::WantsRawCommandString()
117{
118    if (IsValid())
119        return m_underlying_command_sp->WantsRawCommandString();
120    return false;
121}
122
123bool
124CommandAlias::WantsCompletion()
125{
126    if (IsValid())
127        return m_underlying_command_sp->WantsCompletion();
128    return false;
129}
130
131int
132CommandAlias::HandleCompletion (Args &input,
133                  int &cursor_index,
134                  int &cursor_char_position,
135                  int match_start_point,
136                  int max_return_elements,
137                  bool &word_complete,
138                  StringList &matches)
139{
140    if (IsValid())
141        return m_underlying_command_sp->HandleCompletion(input,
142                                                         cursor_index,
143                                                         cursor_char_position,
144                                                         match_start_point,
145                                                         max_return_elements,
146                                                         word_complete,
147                                                         matches);
148    return -1;
149}
150
151int
152CommandAlias::HandleArgumentCompletion (Args &input,
153                          int &cursor_index,
154                          int &cursor_char_position,
155                          OptionElementVector &opt_element_vector,
156                          int match_start_point,
157                          int max_return_elements,
158                          bool &word_complete,
159                          StringList &matches)
160{
161    if (IsValid())
162        return m_underlying_command_sp->HandleArgumentCompletion(input,
163                                                                 cursor_index,
164                                                                 cursor_char_position,
165                                                                 opt_element_vector,
166                                                                 match_start_point,
167                                                                 max_return_elements,
168                                                                 word_complete,
169                                                                 matches);
170    return -1;
171}
172
173Options*
174CommandAlias::GetOptions()
175{
176    if (IsValid())
177        return m_underlying_command_sp->GetOptions();
178    return nullptr;
179}
180
181bool
182CommandAlias::Execute(const char *args_string, CommandReturnObject &result)
183{
184    llvm_unreachable("CommandAlias::Execute is not to be called");
185}
186
187void
188CommandAlias::GetAliasExpansion (StreamString &help_string)
189{
190    const char* command_name = m_underlying_command_sp->GetCommandName();
191    help_string.Printf ("'%s", command_name);
192
193    if (m_option_args_sp)
194    {
195        OptionArgVector *options = m_option_args_sp.get();
196        for (size_t i = 0; i < options->size(); ++i)
197        {
198            OptionArgPair cur_option = (*options)[i];
199            std::string opt = cur_option.first;
200            OptionArgValue value_pair = cur_option.second;
201            std::string value = value_pair.second;
202            if (opt.compare("<argument>") == 0)
203            {
204                help_string.Printf (" %s", value.c_str());
205            }
206            else
207            {
208                help_string.Printf (" %s", opt.c_str());
209                if ((value.compare ("<no-argument>") != 0)
210                    && (value.compare ("<need-argument") != 0))
211                {
212                    help_string.Printf (" %s", value.c_str());
213                }
214            }
215        }
216    }
217
218    help_string.Printf ("'");
219}
220
221bool
222CommandAlias::IsDashDashCommand ()
223{
224    if (m_is_dashdash_alias == eLazyBoolCalculate)
225    {
226        m_is_dashdash_alias = eLazyBoolNo;
227        if (IsValid())
228        {
229            for (const OptionArgPair& opt_arg : *GetOptionArguments())
230            {
231                if (opt_arg.first == "<argument>" &&
232                    !opt_arg.second.second.empty() &&
233                    llvm::StringRef(opt_arg.second.second).endswith("--"))
234                {
235                    m_is_dashdash_alias = eLazyBoolYes;
236                    break;
237                }
238            }
239            // if this is a nested alias, it may be adding arguments on top of an already dash-dash alias
240            if ((m_is_dashdash_alias == eLazyBoolNo) && IsNestedAlias())
241                m_is_dashdash_alias = (GetUnderlyingCommand()->IsDashDashCommand() ? eLazyBoolYes : eLazyBoolNo);
242        }
243    }
244    return (m_is_dashdash_alias == eLazyBoolYes);
245}
246
247bool
248CommandAlias::IsNestedAlias ()
249{
250    if (GetUnderlyingCommand())
251        return GetUnderlyingCommand()->IsAlias();
252    return false;
253}
254
255std::pair<lldb::CommandObjectSP, OptionArgVectorSP>
256CommandAlias::Desugar ()
257{
258    auto underlying = GetUnderlyingCommand();
259    if (!underlying)
260        return {nullptr,nullptr};
261
262    if (underlying->IsAlias())
263    {
264        auto desugared = ((CommandAlias*)underlying.get())->Desugar();
265        auto options = GetOptionArguments();
266        options->insert(options->begin(), desugared.second->begin(), desugared.second->end());
267        return {desugared.first,options};
268    }
269
270    return {underlying,GetOptionArguments()};
271}
272
273// allow CommandAlias objects to provide their own help, but fallback to the info
274// for the underlying command if no customization has been provided
275void
276CommandAlias::SetHelp (const char * str)
277{
278    this->CommandObject::SetHelp(str);
279    m_did_set_help = true;
280}
281
282void
283CommandAlias::SetHelpLong (const char * str)
284{
285    this->CommandObject::SetHelpLong(str);
286    m_did_set_help_long = true;
287}
288
289const char*
290CommandAlias::GetHelp ()
291{
292    if (!m_cmd_help_short.empty() || m_did_set_help)
293        return m_cmd_help_short.c_str();
294    if (IsValid())
295        return m_underlying_command_sp->GetHelp();
296    return nullptr;
297}
298
299const char*
300CommandAlias::GetHelpLong ()
301{
302    if (!m_cmd_help_long.empty() || m_did_set_help_long)
303        return m_cmd_help_long.c_str();
304    if (IsValid())
305        return m_underlying_command_sp->GetHelpLong();
306    return nullptr;
307}
308