1 //===-- CommandObjectRegexCommand.cpp -------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "CommandObjectRegexCommand.h" 10 #include "lldb/Interpreter/CommandInterpreter.h" 11 #include "lldb/Interpreter/CommandReturnObject.h" 12 13 #include "llvm/Support/Errc.h" 14 #include "llvm/Support/Error.h" 15 16 using namespace lldb; 17 using namespace lldb_private; 18 19 // CommandObjectRegexCommand constructor 20 CommandObjectRegexCommand::CommandObjectRegexCommand( 21 CommandInterpreter &interpreter, llvm::StringRef name, llvm::StringRef help, 22 llvm::StringRef syntax, uint32_t completion_type_mask, bool is_removable) 23 : CommandObjectRaw(interpreter, name, help, syntax), 24 m_completion_type_mask(completion_type_mask), 25 m_is_removable(is_removable) {} 26 27 // Destructor 28 CommandObjectRegexCommand::~CommandObjectRegexCommand() = default; 29 30 llvm::Expected<std::string> CommandObjectRegexCommand::SubstituteVariables( 31 llvm::StringRef input, 32 const llvm::SmallVectorImpl<llvm::StringRef> &replacements) { 33 std::string buffer; 34 llvm::raw_string_ostream output(buffer); 35 36 llvm::SmallVector<llvm::StringRef, 4> parts; 37 input.split(parts, '%'); 38 39 output << parts[0]; 40 for (llvm::StringRef part : drop_begin(parts)) { 41 size_t idx = 0; 42 if (part.consumeInteger(10, idx)) 43 output << '%'; 44 else if (idx < replacements.size()) 45 output << replacements[idx]; 46 else 47 return llvm::make_error<llvm::StringError>( 48 llvm::formatv("%{0} is out of range: not enough arguments specified", 49 idx), 50 llvm::errc::invalid_argument); 51 output << part; 52 } 53 54 return output.str(); 55 } 56 57 void CommandObjectRegexCommand::DoExecute(llvm::StringRef command, 58 CommandReturnObject &result) { 59 EntryCollection::const_iterator pos, end = m_entries.end(); 60 for (pos = m_entries.begin(); pos != end; ++pos) { 61 llvm::SmallVector<llvm::StringRef, 4> matches; 62 if (pos->regex.Execute(command, &matches)) { 63 llvm::Expected<std::string> new_command = 64 SubstituteVariables(pos->command, matches); 65 if (!new_command) { 66 result.SetError(new_command.takeError()); 67 return; 68 } 69 70 // Interpret the new command and return this as the result! 71 if (m_interpreter.GetExpandRegexAliases()) 72 result.GetOutputStream().Printf("%s\n", new_command->c_str()); 73 // We don't have to pass an override_context here, as the command that 74 // called us should have set up the context appropriately. 75 bool force_repeat_command = true; 76 m_interpreter.HandleCommand(new_command->c_str(), eLazyBoolNo, result, 77 force_repeat_command); 78 return; 79 } 80 } 81 result.SetStatus(eReturnStatusFailed); 82 if (!GetSyntax().empty()) 83 result.AppendError(GetSyntax()); 84 else 85 result.GetErrorStream() << "Command contents '" << command 86 << "' failed to match any " 87 "regular expression in the '" 88 << m_cmd_name << "' regex "; 89 } 90 91 bool CommandObjectRegexCommand::AddRegexCommand(llvm::StringRef re_cstr, 92 llvm::StringRef command_cstr) { 93 m_entries.resize(m_entries.size() + 1); 94 // Only add the regular expression if it compiles 95 m_entries.back().regex = RegularExpression(re_cstr); 96 if (m_entries.back().regex.IsValid()) { 97 m_entries.back().command = command_cstr.str(); 98 return true; 99 } 100 // The regex didn't compile... 101 m_entries.pop_back(); 102 return false; 103 } 104 105 void CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) { 106 if (m_completion_type_mask) { 107 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 108 GetCommandInterpreter(), m_completion_type_mask, request, nullptr); 109 } 110 } 111