Files
2026-06-09 00:22:22 -05:00

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