1*9390b346SJonas Devlieghere //===-- CommandObjectRegexCommand.cpp -------------------------------------===// 2*9390b346SJonas Devlieghere // 3*9390b346SJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*9390b346SJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information. 5*9390b346SJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*9390b346SJonas Devlieghere // 7*9390b346SJonas Devlieghere //===----------------------------------------------------------------------===// 8*9390b346SJonas Devlieghere 9*9390b346SJonas Devlieghere #include "CommandObjectRegexCommand.h" 10*9390b346SJonas Devlieghere #include "lldb/Interpreter/CommandInterpreter.h" 11*9390b346SJonas Devlieghere #include "lldb/Interpreter/CommandReturnObject.h" 12*9390b346SJonas Devlieghere 13*9390b346SJonas Devlieghere using namespace lldb; 14*9390b346SJonas Devlieghere using namespace lldb_private; 15*9390b346SJonas Devlieghere 16*9390b346SJonas Devlieghere // CommandObjectRegexCommand constructor 17*9390b346SJonas Devlieghere CommandObjectRegexCommand::CommandObjectRegexCommand( 18*9390b346SJonas Devlieghere CommandInterpreter &interpreter, llvm::StringRef name, llvm::StringRef help, 19*9390b346SJonas Devlieghere llvm::StringRef syntax, uint32_t max_matches, uint32_t completion_type_mask, 20*9390b346SJonas Devlieghere bool is_removable) 21*9390b346SJonas Devlieghere : CommandObjectRaw(interpreter, name, help, syntax), 22*9390b346SJonas Devlieghere m_max_matches(max_matches), m_completion_type_mask(completion_type_mask), 23*9390b346SJonas Devlieghere m_entries(), m_is_removable(is_removable) {} 24*9390b346SJonas Devlieghere 25*9390b346SJonas Devlieghere // Destructor 26*9390b346SJonas Devlieghere CommandObjectRegexCommand::~CommandObjectRegexCommand() {} 27*9390b346SJonas Devlieghere 28*9390b346SJonas Devlieghere bool CommandObjectRegexCommand::DoExecute(llvm::StringRef command, 29*9390b346SJonas Devlieghere CommandReturnObject &result) { 30*9390b346SJonas Devlieghere EntryCollection::const_iterator pos, end = m_entries.end(); 31*9390b346SJonas Devlieghere for (pos = m_entries.begin(); pos != end; ++pos) { 32*9390b346SJonas Devlieghere llvm::SmallVector<llvm::StringRef, 4> matches; 33*9390b346SJonas Devlieghere if (pos->regex.Execute(command, &matches)) { 34*9390b346SJonas Devlieghere std::string new_command(pos->command); 35*9390b346SJonas Devlieghere char percent_var[8]; 36*9390b346SJonas Devlieghere size_t idx, percent_var_idx; 37*9390b346SJonas Devlieghere for (uint32_t match_idx = 1; match_idx <= m_max_matches; ++match_idx) { 38*9390b346SJonas Devlieghere if (match_idx < matches.size()) { 39*9390b346SJonas Devlieghere const std::string match_str = matches[match_idx].str(); 40*9390b346SJonas Devlieghere const int percent_var_len = 41*9390b346SJonas Devlieghere ::snprintf(percent_var, sizeof(percent_var), "%%%u", match_idx); 42*9390b346SJonas Devlieghere for (idx = 0; (percent_var_idx = new_command.find( 43*9390b346SJonas Devlieghere percent_var, idx)) != std::string::npos;) { 44*9390b346SJonas Devlieghere new_command.erase(percent_var_idx, percent_var_len); 45*9390b346SJonas Devlieghere new_command.insert(percent_var_idx, match_str); 46*9390b346SJonas Devlieghere idx += percent_var_idx + match_str.size(); 47*9390b346SJonas Devlieghere } 48*9390b346SJonas Devlieghere } 49*9390b346SJonas Devlieghere } 50*9390b346SJonas Devlieghere // Interpret the new command and return this as the result! 51*9390b346SJonas Devlieghere if (m_interpreter.GetExpandRegexAliases()) 52*9390b346SJonas Devlieghere result.GetOutputStream().Printf("%s\n", new_command.c_str()); 53*9390b346SJonas Devlieghere // Pass in true for "no context switching". The command that called us 54*9390b346SJonas Devlieghere // should have set up the context appropriately, we shouldn't have to 55*9390b346SJonas Devlieghere // redo that. 56*9390b346SJonas Devlieghere return m_interpreter.HandleCommand( 57*9390b346SJonas Devlieghere new_command.c_str(), eLazyBoolCalculate, result, nullptr, true, true); 58*9390b346SJonas Devlieghere } 59*9390b346SJonas Devlieghere } 60*9390b346SJonas Devlieghere result.SetStatus(eReturnStatusFailed); 61*9390b346SJonas Devlieghere if (!GetSyntax().empty()) 62*9390b346SJonas Devlieghere result.AppendError(GetSyntax()); 63*9390b346SJonas Devlieghere else 64*9390b346SJonas Devlieghere result.GetOutputStream() << "Command contents '" << command 65*9390b346SJonas Devlieghere << "' failed to match any " 66*9390b346SJonas Devlieghere "regular expression in the '" 67*9390b346SJonas Devlieghere << m_cmd_name << "' regex "; 68*9390b346SJonas Devlieghere return false; 69*9390b346SJonas Devlieghere } 70*9390b346SJonas Devlieghere 71*9390b346SJonas Devlieghere bool CommandObjectRegexCommand::AddRegexCommand(llvm::StringRef re_cstr, 72*9390b346SJonas Devlieghere llvm::StringRef command_cstr) { 73*9390b346SJonas Devlieghere m_entries.resize(m_entries.size() + 1); 74*9390b346SJonas Devlieghere // Only add the regular expression if it compiles 75*9390b346SJonas Devlieghere m_entries.back().regex = RegularExpression(re_cstr); 76*9390b346SJonas Devlieghere if (m_entries.back().regex.IsValid()) { 77*9390b346SJonas Devlieghere m_entries.back().command = command_cstr.str(); 78*9390b346SJonas Devlieghere return true; 79*9390b346SJonas Devlieghere } 80*9390b346SJonas Devlieghere // The regex didn't compile... 81*9390b346SJonas Devlieghere m_entries.pop_back(); 82*9390b346SJonas Devlieghere return false; 83*9390b346SJonas Devlieghere } 84*9390b346SJonas Devlieghere 85*9390b346SJonas Devlieghere void CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) { 86*9390b346SJonas Devlieghere if (m_completion_type_mask) { 87*9390b346SJonas Devlieghere CommandCompletions::InvokeCommonCompletionCallbacks( 88*9390b346SJonas Devlieghere GetCommandInterpreter(), m_completion_type_mask, request, nullptr); 89*9390b346SJonas Devlieghere } 90*9390b346SJonas Devlieghere } 91