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 19 using namespace lldb; 20 using namespace lldb_private; 21 22 static bool 23 ProcessAliasOptionsArgs (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 75 CommandAlias::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), 87 m_underlying_command_sp(), 88 m_option_string(options_args ? options_args : ""), 89 m_option_args_sp(new OptionArgVector), 90 m_is_dashdash_alias(eLazyBoolCalculate), 91 m_did_set_help(false), 92 m_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 115 bool 116 CommandAlias::WantsRawCommandString() 117 { 118 if (IsValid()) 119 return m_underlying_command_sp->WantsRawCommandString(); 120 return false; 121 } 122 123 bool 124 CommandAlias::WantsCompletion() 125 { 126 if (IsValid()) 127 return m_underlying_command_sp->WantsCompletion(); 128 return false; 129 } 130 131 int 132 CommandAlias::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 151 int 152 CommandAlias::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 173 Options* 174 CommandAlias::GetOptions() 175 { 176 if (IsValid()) 177 return m_underlying_command_sp->GetOptions(); 178 return nullptr; 179 } 180 181 bool 182 CommandAlias::Execute(const char *args_string, CommandReturnObject &result) 183 { 184 llvm_unreachable("CommandAlias::Execute is not to be called"); 185 } 186 187 void 188 CommandAlias::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 221 bool 222 CommandAlias::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 247 bool 248 CommandAlias::IsNestedAlias () 249 { 250 if (GetUnderlyingCommand()) 251 return GetUnderlyingCommand()->IsAlias(); 252 return false; 253 } 254 255 std::pair<lldb::CommandObjectSP, OptionArgVectorSP> 256 CommandAlias::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 275 void 276 CommandAlias::SetHelp (const char * str) 277 { 278 this->CommandObject::SetHelp(str); 279 m_did_set_help = true; 280 } 281 282 void 283 CommandAlias::SetHelpLong (const char * str) 284 { 285 this->CommandObject::SetHelpLong(str); 286 m_did_set_help_long = true; 287 } 288 289 const char* 290 CommandAlias::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 299 const char* 300 CommandAlias::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