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