88 lines
2.2 KiB
C++
88 lines
2.2 KiB
C++
#include "sedpp/Regex.h"
|
|
|
|
#include <stdexcept>
|
|
|
|
namespace sedpp {
|
|
|
|
Regex::Regex(const std::string &pattern, const Options &options,
|
|
bool ignoreCase, bool multiline) {
|
|
int flags = 0;
|
|
// Keep regex flavor decisions here so compiler-normalized patterns can be
|
|
// reused by addresses and substitutions without duplicating regcomp flags.
|
|
if (options.extendedRegex) {
|
|
flags |= REG_EXTENDED;
|
|
}
|
|
if (ignoreCase) {
|
|
flags |= REG_ICASE;
|
|
}
|
|
if (multiline) {
|
|
flags |= REG_NEWLINE;
|
|
}
|
|
|
|
const int rc = ::regcomp(®ex_, pattern.c_str(), flags);
|
|
if (rc != 0) {
|
|
char message[256];
|
|
::regerror(rc, ®ex_, message, sizeof(message));
|
|
throw std::runtime_error(message);
|
|
}
|
|
compiled_ = true;
|
|
}
|
|
|
|
Regex::Regex(Regex &&other) noexcept {
|
|
// regex_t is a C resource; moving transfers the compiled object and prevents
|
|
// the source wrapper from freeing it.
|
|
regex_ = other.regex_;
|
|
compiled_ = other.compiled_;
|
|
other.compiled_ = false;
|
|
}
|
|
|
|
Regex &Regex::operator=(Regex &&other) noexcept {
|
|
if (this != &other) {
|
|
if (compiled_) {
|
|
::regfree(®ex_);
|
|
}
|
|
regex_ = other.regex_;
|
|
compiled_ = other.compiled_;
|
|
other.compiled_ = false;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
Regex::~Regex() {
|
|
if (compiled_) {
|
|
::regfree(®ex_);
|
|
}
|
|
}
|
|
|
|
std::optional<Match> Regex::search(const std::string &text,
|
|
std::size_t start) const {
|
|
constexpr std::size_t kMaxGroups = 10;
|
|
Match match;
|
|
match.groups.resize(kMaxGroups);
|
|
|
|
const char *base = text.c_str();
|
|
// Searches after byte 0 should not let ^ match the original beginning again.
|
|
const int eflags = start == 0 ? 0 : REG_NOTBOL;
|
|
const int rc = ::regexec(®ex_, base + start, match.groups.size(),
|
|
match.groups.data(), eflags);
|
|
if (rc == REG_NOMATCH) {
|
|
return std::nullopt;
|
|
}
|
|
if (rc != 0) {
|
|
char message[256];
|
|
::regerror(rc, ®ex_, message, sizeof(message));
|
|
throw std::runtime_error(message);
|
|
}
|
|
|
|
for (regmatch_t &group : match.groups) {
|
|
if (group.rm_so >= 0) {
|
|
// regexec saw base + start, so convert offsets back into the full string.
|
|
group.rm_so += static_cast<regoff_t>(start);
|
|
group.rm_eo += static_cast<regoff_t>(start);
|
|
}
|
|
}
|
|
return match;
|
|
}
|
|
|
|
} // namespace sedpp
|