1e8d8bef9SDimitry Andric //===-- CommandObjectRegexCommand.cpp -------------------------------------===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric 9e8d8bef9SDimitry Andric #include "CommandObjectRegexCommand.h" 10e8d8bef9SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h" 11e8d8bef9SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 12e8d8bef9SDimitry Andric 1381ad6265SDimitry Andric #include "llvm/Support/Errc.h" 1481ad6265SDimitry Andric #include "llvm/Support/Error.h" 1581ad6265SDimitry Andric 16e8d8bef9SDimitry Andric using namespace lldb; 17e8d8bef9SDimitry Andric using namespace lldb_private; 18e8d8bef9SDimitry Andric 19e8d8bef9SDimitry Andric // CommandObjectRegexCommand constructor 20e8d8bef9SDimitry Andric CommandObjectRegexCommand::CommandObjectRegexCommand( 21e8d8bef9SDimitry Andric CommandInterpreter &interpreter, llvm::StringRef name, llvm::StringRef help, 22*06c3fb27SDimitry Andric llvm::StringRef syntax, uint32_t completion_type_mask, bool is_removable) 23e8d8bef9SDimitry Andric : CommandObjectRaw(interpreter, name, help, syntax), 24*06c3fb27SDimitry Andric m_completion_type_mask(completion_type_mask), 2504eeddc0SDimitry Andric m_is_removable(is_removable) {} 26e8d8bef9SDimitry Andric 27e8d8bef9SDimitry Andric // Destructor 28fe6060f1SDimitry Andric CommandObjectRegexCommand::~CommandObjectRegexCommand() = default; 29e8d8bef9SDimitry Andric 3081ad6265SDimitry Andric llvm::Expected<std::string> CommandObjectRegexCommand::SubstituteVariables( 3181ad6265SDimitry Andric llvm::StringRef input, 3281ad6265SDimitry Andric const llvm::SmallVectorImpl<llvm::StringRef> &replacements) { 3381ad6265SDimitry Andric std::string buffer; 3481ad6265SDimitry Andric llvm::raw_string_ostream output(buffer); 3581ad6265SDimitry Andric 3681ad6265SDimitry Andric llvm::SmallVector<llvm::StringRef, 4> parts; 3781ad6265SDimitry Andric input.split(parts, '%'); 3881ad6265SDimitry Andric 3981ad6265SDimitry Andric output << parts[0]; 4081ad6265SDimitry Andric for (llvm::StringRef part : drop_begin(parts)) { 4181ad6265SDimitry Andric size_t idx = 0; 4281ad6265SDimitry Andric if (part.consumeInteger(10, idx)) 4381ad6265SDimitry Andric output << '%'; 4481ad6265SDimitry Andric else if (idx < replacements.size()) 4581ad6265SDimitry Andric output << replacements[idx]; 4681ad6265SDimitry Andric else 4781ad6265SDimitry Andric return llvm::make_error<llvm::StringError>( 4881ad6265SDimitry Andric llvm::formatv("%{0} is out of range: not enough arguments specified", 4981ad6265SDimitry Andric idx), 5081ad6265SDimitry Andric llvm::errc::invalid_argument); 5181ad6265SDimitry Andric output << part; 5281ad6265SDimitry Andric } 5381ad6265SDimitry Andric 5481ad6265SDimitry Andric return output.str(); 5581ad6265SDimitry Andric } 5681ad6265SDimitry Andric 57e8d8bef9SDimitry Andric bool CommandObjectRegexCommand::DoExecute(llvm::StringRef command, 58e8d8bef9SDimitry Andric CommandReturnObject &result) { 59e8d8bef9SDimitry Andric EntryCollection::const_iterator pos, end = m_entries.end(); 60e8d8bef9SDimitry Andric for (pos = m_entries.begin(); pos != end; ++pos) { 61e8d8bef9SDimitry Andric llvm::SmallVector<llvm::StringRef, 4> matches; 62e8d8bef9SDimitry Andric if (pos->regex.Execute(command, &matches)) { 6381ad6265SDimitry Andric llvm::Expected<std::string> new_command = 6481ad6265SDimitry Andric SubstituteVariables(pos->command, matches); 6581ad6265SDimitry Andric if (!new_command) { 6681ad6265SDimitry Andric result.SetError(new_command.takeError()); 6781ad6265SDimitry Andric return false; 68e8d8bef9SDimitry Andric } 6981ad6265SDimitry Andric 70e8d8bef9SDimitry Andric // Interpret the new command and return this as the result! 71e8d8bef9SDimitry Andric if (m_interpreter.GetExpandRegexAliases()) 7281ad6265SDimitry Andric result.GetOutputStream().Printf("%s\n", new_command->c_str()); 7381ad6265SDimitry Andric // We don't have to pass an override_context here, as the command that 7481ad6265SDimitry Andric // called us should have set up the context appropriately. 75*06c3fb27SDimitry Andric bool force_repeat_command = true; 76*06c3fb27SDimitry Andric return m_interpreter.HandleCommand(new_command->c_str(), eLazyBoolNo, 77*06c3fb27SDimitry Andric result, force_repeat_command); 78e8d8bef9SDimitry Andric } 79e8d8bef9SDimitry Andric } 80e8d8bef9SDimitry Andric result.SetStatus(eReturnStatusFailed); 81e8d8bef9SDimitry Andric if (!GetSyntax().empty()) 82e8d8bef9SDimitry Andric result.AppendError(GetSyntax()); 83e8d8bef9SDimitry Andric else 8481ad6265SDimitry Andric result.GetErrorStream() << "Command contents '" << command 85e8d8bef9SDimitry Andric << "' failed to match any " 86e8d8bef9SDimitry Andric "regular expression in the '" 87e8d8bef9SDimitry Andric << m_cmd_name << "' regex "; 88e8d8bef9SDimitry Andric return false; 89e8d8bef9SDimitry Andric } 90e8d8bef9SDimitry Andric 91e8d8bef9SDimitry Andric bool CommandObjectRegexCommand::AddRegexCommand(llvm::StringRef re_cstr, 92e8d8bef9SDimitry Andric llvm::StringRef command_cstr) { 93e8d8bef9SDimitry Andric m_entries.resize(m_entries.size() + 1); 94e8d8bef9SDimitry Andric // Only add the regular expression if it compiles 95e8d8bef9SDimitry Andric m_entries.back().regex = RegularExpression(re_cstr); 96e8d8bef9SDimitry Andric if (m_entries.back().regex.IsValid()) { 97e8d8bef9SDimitry Andric m_entries.back().command = command_cstr.str(); 98e8d8bef9SDimitry Andric return true; 99e8d8bef9SDimitry Andric } 100e8d8bef9SDimitry Andric // The regex didn't compile... 101e8d8bef9SDimitry Andric m_entries.pop_back(); 102e8d8bef9SDimitry Andric return false; 103e8d8bef9SDimitry Andric } 104e8d8bef9SDimitry Andric 105e8d8bef9SDimitry Andric void CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) { 106e8d8bef9SDimitry Andric if (m_completion_type_mask) { 107*06c3fb27SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 108e8d8bef9SDimitry Andric GetCommandInterpreter(), m_completion_type_mask, request, nullptr); 109e8d8bef9SDimitry Andric } 110e8d8bef9SDimitry Andric } 111