initial commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user