#pragma once #include #include #include #include #include #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 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 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 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 &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 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 readOffsets_; int finalStatus_ = 0; }; } // namespace sedpp