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