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