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