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 max_matches, uint32_t completion_type_mask, 23 bool is_removable) 24 : CommandObjectRaw(interpreter, name, help, syntax), 25 m_max_matches(max_matches), m_completion_type_mask(completion_type_mask), 26 m_is_removable(is_removable) {} 27 28 // Destructor 29 CommandObjectRegexCommand::~CommandObjectRegexCommand() = default; 30 31 llvm::Expected<std::string> CommandObjectRegexCommand::SubstituteVariables( 32 llvm::StringRef input, 33 const llvm::SmallVectorImpl<llvm::StringRef> &replacements) { 34 std::string buffer; 35 llvm::raw_string_ostream output(buffer); 36 37 llvm::SmallVector<llvm::StringRef, 4> parts; 38 input.split(parts, '%'); 39 40 output << parts[0]; 41 for (llvm::StringRef part : drop_begin(parts)) { 42 size_t idx = 0; 43 if (part.consumeInteger(10, idx)) 44 output << '%'; 45 else if (idx < replacements.size()) 46 output << replacements[idx]; 47 else 48 return llvm::make_error<llvm::StringError>( 49 llvm::formatv("%{0} is out of range: not enough arguments specified", 50 idx), 51 llvm::errc::invalid_argument); 52 output << part; 53 } 54 55 return output.str(); 56 } 57 58 bool CommandObjectRegexCommand::DoExecute(llvm::StringRef command, 59 CommandReturnObject &result) { 60 EntryCollection::const_iterator pos, end = m_entries.end(); 61 for (pos = m_entries.begin(); pos != end; ++pos) { 62 llvm::SmallVector<llvm::StringRef, 4> matches; 63 if (pos->regex.Execute(command, &matches)) { 64 llvm::Expected<std::string> new_command = 65 SubstituteVariables(pos->command, matches); 66 if (!new_command) { 67 result.SetError(new_command.takeError()); 68 return false; 69 } 70 71 // Interpret the new command and return this as the result! 72 if (m_interpreter.GetExpandRegexAliases()) 73 result.GetOutputStream().Printf("%s\n", new_command->c_str()); 74 // We don't have to pass an override_context here, as the command that 75 // called us should have set up the context appropriately. 76 return m_interpreter.HandleCommand(new_command->c_str(), 77 eLazyBoolNo, result); 78 } 79 } 80 result.SetStatus(eReturnStatusFailed); 81 if (!GetSyntax().empty()) 82 result.AppendError(GetSyntax()); 83 else 84 result.GetErrorStream() << "Command contents '" << command 85 << "' failed to match any " 86 "regular expression in the '" 87 << m_cmd_name << "' regex "; 88 return false; 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 CommandCompletions::InvokeCommonCompletionCallbacks( 108 GetCommandInterpreter(), m_completion_type_mask, request, nullptr); 109 } 110 } 111