77 lines
2.8 KiB
C++
77 lines
2.8 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "sedpp/Command.h"
|
|
#include "sedpp/Input.h"
|
|
#include "sedpp/Options.h"
|
|
|
|
namespace sedpp {
|
|
|
|
// Executes a compiled sed program against the loaded input records. This class
|
|
// owns the mutable pieces of sed state: hold space, last successful substitution,
|
|
// last regex, per-command ranges, and read offsets for R commands.
|
|
class Runner {
|
|
public:
|
|
Runner(Options options, Program program,
|
|
std::unordered_map<std::string, std::size_t> labels);
|
|
|
|
[[nodiscard]] int run();
|
|
|
|
private:
|
|
// One sed cycle starts with a single input record in pattern space. Commands
|
|
// may append more input (N/n), delete the cycle, or request a quit before the
|
|
// automatic print phase.
|
|
struct Cycle {
|
|
std::string pattern;
|
|
bool hadDelimiter = false;
|
|
std::string fileName;
|
|
std::uint64_t lineNumber = 0;
|
|
std::uint64_t fileLineNumber = 0;
|
|
bool lastInFile = false;
|
|
bool lastOverall = false;
|
|
bool deleted = false;
|
|
bool quit = false;
|
|
int exitCode = 0;
|
|
std::vector<std::string> appendQueue;
|
|
};
|
|
|
|
// runRecords is shared by normal output and in-place editing so in-place mode
|
|
// can render to memory before atomically replacing the source file.
|
|
[[nodiscard]] std::string runRecords(std::vector<Record> records);
|
|
[[nodiscard]] bool commandApplies(Command &command, const Cycle &cycle);
|
|
[[nodiscard]] bool addressMatches(const Address &address, const Cycle &cycle);
|
|
void execute(Command &command, Cycle &cycle, std::size_t &pc,
|
|
std::vector<Record> &records, std::size_t &recordIndex,
|
|
class Output &output);
|
|
bool substitute(Command &command, Cycle &cycle, class Output &output);
|
|
std::string executeShell(const std::string &command,
|
|
bool stripTrailingDelimiter = true) const;
|
|
void emitAppendQueue(Cycle &cycle, class Output &output);
|
|
void queueFile(Cycle &cycle, const std::string &path);
|
|
void queueNextFileLine(Cycle &cycle, const std::string &path);
|
|
|
|
Options options_;
|
|
Program program_;
|
|
std::unordered_map<std::string, std::size_t> labels_;
|
|
// Branch commands t/T observe whether any s command has succeeded since the
|
|
// last input-cycle start or branch test.
|
|
bool lastSubstitutionSucceeded_ = false;
|
|
// Empty regex addresses and empty s patterns reuse this value, matching sed's
|
|
// "last regular expression" rule.
|
|
std::string lastRegex_;
|
|
// Hold space has its own delimiter bit because pattern/hold exchanges must
|
|
// preserve whether the original input ended with a record separator.
|
|
std::string holdSpace_;
|
|
bool holdHadDelimiter_ = true;
|
|
// R reads one line per invocation per path; offsets remember the next line.
|
|
std::unordered_map<std::string, std::size_t> readOffsets_;
|
|
int finalStatus_ = 0;
|
|
};
|
|
|
|
} // namespace sedpp
|