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