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 // Pass in true for "no context switching". The command that called us 75 // should have set up the context appropriately, we shouldn't have to 76 // redo that. 77 return m_interpreter.HandleCommand(new_command->c_str(), 78 eLazyBoolCalculate, result); 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 return false; 90 } 91 92 bool CommandObjectRegexCommand::AddRegexCommand(llvm::StringRef re_cstr, 93 llvm::StringRef command_cstr) { 94 m_entries.resize(m_entries.size() + 1); 95 // Only add the regular expression if it compiles 96 m_entries.back().regex = RegularExpression(re_cstr); 97 if (m_entries.back().regex.IsValid()) { 98 m_entries.back().command = command_cstr.str(); 99 return true; 100 } 101 // The regex didn't compile... 102 m_entries.pop_back(); 103 return false; 104 } 105 106 void CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) { 107 if (m_completion_type_mask) { 108 CommandCompletions::InvokeCommonCompletionCallbacks( 109 GetCommandInterpreter(), m_completion_type_mask, request, nullptr); 110 } 111 } 112