CommandAlias.cpp revision 304274
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