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