1254721Semaste//===-- CommandObjectRegexCommand.cpp ---------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9254721Semaste#include "lldb/Interpreter/CommandObjectRegexCommand.h"
10254721Semaste
11254721Semaste#include "lldb/Interpreter/CommandInterpreter.h"
12254721Semaste#include "lldb/Interpreter/CommandReturnObject.h"
13254721Semaste
14254721Semasteusing namespace lldb;
15254721Semasteusing namespace lldb_private;
16254721Semaste
17254721Semaste// CommandObjectRegexCommand constructor
18314564SdimCommandObjectRegexCommand::CommandObjectRegexCommand(
19314564Sdim    CommandInterpreter &interpreter, llvm::StringRef name, llvm::StringRef help,
20314564Sdim  llvm::StringRef syntax, uint32_t max_matches, uint32_t completion_type_mask,
21314564Sdim    bool is_removable)
22314564Sdim    : CommandObjectRaw(interpreter, name, help, syntax),
23314564Sdim      m_max_matches(max_matches), m_completion_type_mask(completion_type_mask),
24314564Sdim      m_entries(), m_is_removable(is_removable) {}
25254721Semaste
26254721Semaste// Destructor
27314564SdimCommandObjectRegexCommand::~CommandObjectRegexCommand() {}
28254721Semaste
29341825Sdimbool CommandObjectRegexCommand::DoExecute(llvm::StringRef command,
30314564Sdim                                          CommandReturnObject &result) {
31341825Sdim  EntryCollection::const_iterator pos, end = m_entries.end();
32341825Sdim  for (pos = m_entries.begin(); pos != end; ++pos) {
33360784Sdim    llvm::SmallVector<llvm::StringRef, 4> matches;
34360784Sdim    if (pos->regex.Execute(command, &matches)) {
35341825Sdim      std::string new_command(pos->command);
36341825Sdim      char percent_var[8];
37341825Sdim      size_t idx, percent_var_idx;
38341825Sdim      for (uint32_t match_idx = 1; match_idx <= m_max_matches; ++match_idx) {
39360784Sdim        if (match_idx < matches.size()) {
40360784Sdim          const std::string match_str = matches[match_idx].str();
41341825Sdim          const int percent_var_len =
42341825Sdim              ::snprintf(percent_var, sizeof(percent_var), "%%%u", match_idx);
43341825Sdim          for (idx = 0; (percent_var_idx = new_command.find(
44341825Sdim                             percent_var, idx)) != std::string::npos;) {
45341825Sdim            new_command.erase(percent_var_idx, percent_var_len);
46341825Sdim            new_command.insert(percent_var_idx, match_str);
47341825Sdim            idx += percent_var_idx + match_str.size();
48314564Sdim          }
49254721Semaste        }
50314564Sdim      }
51341825Sdim      // Interpret the new command and return this as the result!
52341825Sdim      if (m_interpreter.GetExpandRegexAliases())
53341825Sdim        result.GetOutputStream().Printf("%s\n", new_command.c_str());
54341825Sdim      // Pass in true for "no context switching".  The command that called us
55341825Sdim      // should have set up the context appropriately, we shouldn't have to
56341825Sdim      // redo that.
57341825Sdim      return m_interpreter.HandleCommand(
58341825Sdim          new_command.c_str(), eLazyBoolCalculate, result, nullptr, true, true);
59254721Semaste    }
60314564Sdim  }
61314564Sdim  result.SetStatus(eReturnStatusFailed);
62341825Sdim  if (!GetSyntax().empty())
63341825Sdim    result.AppendError(GetSyntax());
64341825Sdim  else
65341825Sdim    result.GetOutputStream() << "Command contents '" << command
66341825Sdim                             << "' failed to match any "
67341825Sdim                                "regular expression in the '"
68341825Sdim                             << m_cmd_name << "' regex ";
69314564Sdim  return false;
70254721Semaste}
71254721Semaste
72314564Sdimbool CommandObjectRegexCommand::AddRegexCommand(const char *re_cstr,
73314564Sdim                                                const char *command_cstr) {
74314564Sdim  m_entries.resize(m_entries.size() + 1);
75314564Sdim  // Only add the regular expression if it compiles
76360784Sdim  m_entries.back().regex =
77360784Sdim      RegularExpression(llvm::StringRef::withNullAsEmpty(re_cstr));
78360784Sdim  if (m_entries.back().regex.IsValid()) {
79314564Sdim    m_entries.back().command.assign(command_cstr);
80314564Sdim    return true;
81314564Sdim  }
82314564Sdim  // The regex didn't compile...
83314564Sdim  m_entries.pop_back();
84314564Sdim  return false;
85254721Semaste}
86254721Semaste
87360784Sdimvoid CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) {
88314564Sdim  if (m_completion_type_mask) {
89314564Sdim    CommandCompletions::InvokeCommonCompletionCallbacks(
90341825Sdim        GetCommandInterpreter(), m_completion_type_mask, request, nullptr);
91314564Sdim  }
92254721Semaste}
93