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 
132a6dbedfSJonas Devlieghere #include "llvm/Support/Errc.h"
142a6dbedfSJonas Devlieghere #include "llvm/Support/Error.h"
152a6dbedfSJonas Devlieghere 
169390b346SJonas Devlieghere using namespace lldb;
179390b346SJonas Devlieghere using namespace lldb_private;
189390b346SJonas Devlieghere 
199390b346SJonas Devlieghere // 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)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 
SubstituteVariables(llvm::StringRef input,const llvm::SmallVectorImpl<llvm::StringRef> & replacements)312a6dbedfSJonas Devlieghere llvm::Expected<std::string> CommandObjectRegexCommand::SubstituteVariables(
322a6dbedfSJonas Devlieghere     llvm::StringRef input,
332a6dbedfSJonas Devlieghere     const llvm::SmallVectorImpl<llvm::StringRef> &replacements) {
342a6dbedfSJonas Devlieghere   std::string buffer;
352a6dbedfSJonas Devlieghere   llvm::raw_string_ostream output(buffer);
362a6dbedfSJonas Devlieghere 
372a6dbedfSJonas Devlieghere   llvm::SmallVector<llvm::StringRef, 4> parts;
382a6dbedfSJonas Devlieghere   input.split(parts, '%');
392a6dbedfSJonas Devlieghere 
402a6dbedfSJonas Devlieghere   output << parts[0];
412a6dbedfSJonas Devlieghere   for (llvm::StringRef part : drop_begin(parts)) {
422a6dbedfSJonas Devlieghere     size_t idx = 0;
432a6dbedfSJonas Devlieghere     if (part.consumeInteger(10, idx))
442a6dbedfSJonas Devlieghere       output << '%';
452a6dbedfSJonas Devlieghere     else if (idx < replacements.size())
462a6dbedfSJonas Devlieghere       output << replacements[idx];
472a6dbedfSJonas Devlieghere     else
482a6dbedfSJonas Devlieghere       return llvm::make_error<llvm::StringError>(
492a6dbedfSJonas Devlieghere           llvm::formatv("%{0} is out of range: not enough arguments specified",
502a6dbedfSJonas Devlieghere                         idx),
512a6dbedfSJonas Devlieghere           llvm::errc::invalid_argument);
522a6dbedfSJonas Devlieghere     output << part;
532a6dbedfSJonas Devlieghere   }
542a6dbedfSJonas Devlieghere 
552a6dbedfSJonas Devlieghere   return output.str();
562a6dbedfSJonas Devlieghere }
572a6dbedfSJonas Devlieghere 
DoExecute(llvm::StringRef command,CommandReturnObject & result)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)) {
642a6dbedfSJonas Devlieghere       llvm::Expected<std::string> new_command =
652a6dbedfSJonas Devlieghere           SubstituteVariables(pos->command, matches);
662a6dbedfSJonas Devlieghere       if (!new_command) {
672a6dbedfSJonas Devlieghere         result.SetError(new_command.takeError());
682a6dbedfSJonas Devlieghere         return false;
699390b346SJonas Devlieghere       }
702a6dbedfSJonas Devlieghere 
719390b346SJonas Devlieghere       // Interpret the new command and return this as the result!
729390b346SJonas Devlieghere       if (m_interpreter.GetExpandRegexAliases())
732a6dbedfSJonas Devlieghere         result.GetOutputStream().Printf("%s\n", new_command->c_str());
74*8cc8b36fSJim Ingham       // We don't have to pass an override_context here, as the command that
75*8cc8b36fSJim Ingham       // called us should have set up the context appropriately.
762a6dbedfSJonas Devlieghere       return m_interpreter.HandleCommand(new_command->c_str(),
77*8cc8b36fSJim Ingham                                          eLazyBoolNo, result);
789390b346SJonas Devlieghere     }
799390b346SJonas Devlieghere   }
809390b346SJonas Devlieghere   result.SetStatus(eReturnStatusFailed);
819390b346SJonas Devlieghere   if (!GetSyntax().empty())
829390b346SJonas Devlieghere     result.AppendError(GetSyntax());
839390b346SJonas Devlieghere   else
842a6dbedfSJonas Devlieghere     result.GetErrorStream() << "Command contents '" << command
859390b346SJonas Devlieghere                             << "' failed to match any "
869390b346SJonas Devlieghere                                "regular expression in the '"
879390b346SJonas Devlieghere                             << m_cmd_name << "' regex ";
889390b346SJonas Devlieghere   return false;
899390b346SJonas Devlieghere }
909390b346SJonas Devlieghere 
AddRegexCommand(llvm::StringRef re_cstr,llvm::StringRef command_cstr)919390b346SJonas Devlieghere bool CommandObjectRegexCommand::AddRegexCommand(llvm::StringRef re_cstr,
929390b346SJonas Devlieghere                                                 llvm::StringRef command_cstr) {
939390b346SJonas Devlieghere   m_entries.resize(m_entries.size() + 1);
949390b346SJonas Devlieghere   // Only add the regular expression if it compiles
959390b346SJonas Devlieghere   m_entries.back().regex = RegularExpression(re_cstr);
969390b346SJonas Devlieghere   if (m_entries.back().regex.IsValid()) {
979390b346SJonas Devlieghere     m_entries.back().command = command_cstr.str();
989390b346SJonas Devlieghere     return true;
999390b346SJonas Devlieghere   }
1009390b346SJonas Devlieghere   // The regex didn't compile...
1019390b346SJonas Devlieghere   m_entries.pop_back();
1029390b346SJonas Devlieghere   return false;
1039390b346SJonas Devlieghere }
1049390b346SJonas Devlieghere 
HandleCompletion(CompletionRequest & request)1059390b346SJonas Devlieghere void CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) {
1069390b346SJonas Devlieghere   if (m_completion_type_mask) {
1079390b346SJonas Devlieghere     CommandCompletions::InvokeCommonCompletionCallbacks(
1089390b346SJonas Devlieghere         GetCommandInterpreter(), m_completion_type_mask, request, nullptr);
1099390b346SJonas Devlieghere   }
1109390b346SJonas Devlieghere }
111