19390b346SJonas Devlieghere //===-- CommandObjectRegexCommand.cpp -------------------------------------===// 29390b346SJonas Devlieghere // 39390b346SJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 49390b346SJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information. 59390b346SJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 69390b346SJonas Devlieghere // 79390b346SJonas Devlieghere //===----------------------------------------------------------------------===// 89390b346SJonas Devlieghere 99390b346SJonas Devlieghere #include "CommandObjectRegexCommand.h" 109390b346SJonas Devlieghere #include "lldb/Interpreter/CommandInterpreter.h" 119390b346SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h" 129390b346SJonas Devlieghere 13*2a6dbedfSJonas Devlieghere #include "llvm/Support/Errc.h" 14*2a6dbedfSJonas Devlieghere #include "llvm/Support/Error.h" 15*2a6dbedfSJonas Devlieghere 169390b346SJonas Devlieghere using namespace lldb; 179390b346SJonas Devlieghere using namespace lldb_private; 189390b346SJonas Devlieghere 199390b346SJonas Devlieghere // CommandObjectRegexCommand constructor 209390b346SJonas Devlieghere CommandObjectRegexCommand::CommandObjectRegexCommand( 219390b346SJonas Devlieghere CommandInterpreter &interpreter, llvm::StringRef name, llvm::StringRef help, 229390b346SJonas Devlieghere llvm::StringRef syntax, uint32_t max_matches, uint32_t completion_type_mask, 239390b346SJonas Devlieghere bool is_removable) 249390b346SJonas Devlieghere : CommandObjectRaw(interpreter, name, help, syntax), 259390b346SJonas Devlieghere m_max_matches(max_matches), m_completion_type_mask(completion_type_mask), 26abb0ed44SKazu Hirata m_is_removable(is_removable) {} 279390b346SJonas Devlieghere 289390b346SJonas Devlieghere // Destructor 29fd2433e1SJonas Devlieghere CommandObjectRegexCommand::~CommandObjectRegexCommand() = default; 309390b346SJonas Devlieghere 31*2a6dbedfSJonas Devlieghere llvm::Expected<std::string> CommandObjectRegexCommand::SubstituteVariables( 32*2a6dbedfSJonas Devlieghere llvm::StringRef input, 33*2a6dbedfSJonas Devlieghere const llvm::SmallVectorImpl<llvm::StringRef> &replacements) { 34*2a6dbedfSJonas Devlieghere std::string buffer; 35*2a6dbedfSJonas Devlieghere llvm::raw_string_ostream output(buffer); 36*2a6dbedfSJonas Devlieghere 37*2a6dbedfSJonas Devlieghere llvm::SmallVector<llvm::StringRef, 4> parts; 38*2a6dbedfSJonas Devlieghere input.split(parts, '%'); 39*2a6dbedfSJonas Devlieghere 40*2a6dbedfSJonas Devlieghere output << parts[0]; 41*2a6dbedfSJonas Devlieghere for (llvm::StringRef part : drop_begin(parts)) { 42*2a6dbedfSJonas Devlieghere size_t idx = 0; 43*2a6dbedfSJonas Devlieghere if (part.consumeInteger(10, idx)) 44*2a6dbedfSJonas Devlieghere output << '%'; 45*2a6dbedfSJonas Devlieghere else if (idx < replacements.size()) 46*2a6dbedfSJonas Devlieghere output << replacements[idx]; 47*2a6dbedfSJonas Devlieghere else 48*2a6dbedfSJonas Devlieghere return llvm::make_error<llvm::StringError>( 49*2a6dbedfSJonas Devlieghere llvm::formatv("%{0} is out of range: not enough arguments specified", 50*2a6dbedfSJonas Devlieghere idx), 51*2a6dbedfSJonas Devlieghere llvm::errc::invalid_argument); 52*2a6dbedfSJonas Devlieghere output << part; 53*2a6dbedfSJonas Devlieghere } 54*2a6dbedfSJonas Devlieghere 55*2a6dbedfSJonas Devlieghere return output.str(); 56*2a6dbedfSJonas Devlieghere } 57*2a6dbedfSJonas Devlieghere 589390b346SJonas Devlieghere bool CommandObjectRegexCommand::DoExecute(llvm::StringRef command, 599390b346SJonas Devlieghere CommandReturnObject &result) { 609390b346SJonas Devlieghere EntryCollection::const_iterator pos, end = m_entries.end(); 619390b346SJonas Devlieghere for (pos = m_entries.begin(); pos != end; ++pos) { 629390b346SJonas Devlieghere llvm::SmallVector<llvm::StringRef, 4> matches; 639390b346SJonas Devlieghere if (pos->regex.Execute(command, &matches)) { 64*2a6dbedfSJonas Devlieghere llvm::Expected<std::string> new_command = 65*2a6dbedfSJonas Devlieghere SubstituteVariables(pos->command, matches); 66*2a6dbedfSJonas Devlieghere if (!new_command) { 67*2a6dbedfSJonas Devlieghere result.SetError(new_command.takeError()); 68*2a6dbedfSJonas Devlieghere return false; 699390b346SJonas Devlieghere } 70*2a6dbedfSJonas Devlieghere 719390b346SJonas Devlieghere // Interpret the new command and return this as the result! 729390b346SJonas Devlieghere if (m_interpreter.GetExpandRegexAliases()) 73*2a6dbedfSJonas Devlieghere result.GetOutputStream().Printf("%s\n", new_command->c_str()); 749390b346SJonas Devlieghere // Pass in true for "no context switching". The command that called us 759390b346SJonas Devlieghere // should have set up the context appropriately, we shouldn't have to 769390b346SJonas Devlieghere // redo that. 77*2a6dbedfSJonas Devlieghere return m_interpreter.HandleCommand(new_command->c_str(), 7836de94cfSTatyana Krasnukha eLazyBoolCalculate, result); 799390b346SJonas Devlieghere } 809390b346SJonas Devlieghere } 819390b346SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 829390b346SJonas Devlieghere if (!GetSyntax().empty()) 839390b346SJonas Devlieghere result.AppendError(GetSyntax()); 849390b346SJonas Devlieghere else 85*2a6dbedfSJonas Devlieghere result.GetErrorStream() << "Command contents '" << command 869390b346SJonas Devlieghere << "' failed to match any " 879390b346SJonas Devlieghere "regular expression in the '" 889390b346SJonas Devlieghere << m_cmd_name << "' regex "; 899390b346SJonas Devlieghere return false; 909390b346SJonas Devlieghere } 919390b346SJonas Devlieghere 929390b346SJonas Devlieghere bool CommandObjectRegexCommand::AddRegexCommand(llvm::StringRef re_cstr, 939390b346SJonas Devlieghere llvm::StringRef command_cstr) { 949390b346SJonas Devlieghere m_entries.resize(m_entries.size() + 1); 959390b346SJonas Devlieghere // Only add the regular expression if it compiles 969390b346SJonas Devlieghere m_entries.back().regex = RegularExpression(re_cstr); 979390b346SJonas Devlieghere if (m_entries.back().regex.IsValid()) { 989390b346SJonas Devlieghere m_entries.back().command = command_cstr.str(); 999390b346SJonas Devlieghere return true; 1009390b346SJonas Devlieghere } 1019390b346SJonas Devlieghere // The regex didn't compile... 1029390b346SJonas Devlieghere m_entries.pop_back(); 1039390b346SJonas Devlieghere return false; 1049390b346SJonas Devlieghere } 1059390b346SJonas Devlieghere 1069390b346SJonas Devlieghere void CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) { 1079390b346SJonas Devlieghere if (m_completion_type_mask) { 1089390b346SJonas Devlieghere CommandCompletions::InvokeCommonCompletionCallbacks( 1099390b346SJonas Devlieghere GetCommandInterpreter(), m_completion_type_mask, request, nullptr); 1109390b346SJonas Devlieghere } 1119390b346SJonas Devlieghere } 112