blob: 2f5d14160dcc755f858bed5739cd7c895bdf6d4c [file]
/**
@section license License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copyright 2019, Oath Inc.
*/
#include <string>
#include "txn_box/common.h"
#include "txn_box/Rxp.h"
#include "txn_box/Config.h"
using swoc::TextView;
using namespace swoc::literals;
using swoc::Errata;
using swoc::Rv;
Rv<Rxp>
Rxp::parse(TextView const &str, Options const &options)
{
int errc = 0;
size_t err_off = 0;
uint32_t rxp_opt = 0;
if (options.f.nc) {
rxp_opt = PCRE2_CASELESS;
}
auto result = pcre2_compile(reinterpret_cast<unsigned const char *>(str.data()), str.size(), rxp_opt, &errc, &err_off, nullptr);
if (nullptr == result) {
PCRE2_UCHAR err_buff[128];
auto err_size = pcre2_get_error_message(errc, err_buff, sizeof(err_buff));
return Errata(S_ERROR, R"(Failed to parse regular expression - error "{}" [{}] at offset {} in "{}".)",
TextView(reinterpret_cast<char const *>(err_buff), err_size), errc, err_off, str);
}
return {result};
};
int
Rxp::operator()(swoc::TextView text, pcre2_match_data *match) const
{
return pcre2_match(_rxp.get(), reinterpret_cast<PCRE2_SPTR>(text.data()), text.size(), 0, 0, match, nullptr);
}
size_t
Rxp::capture_count() const
{
uint32_t count = 0;
auto result = pcre2_pattern_info(_rxp.get(), PCRE2_INFO_CAPTURECOUNT, &count);
return result == 0 ? count + 1 : 0; // output doesn't reflect capture group 0, apparently.
}
/* ------------------------------------------------------------------------------------ */
RxpOp::RxpOp(Rxp &&rxp) : _raw(std::move(rxp)) {}
RxpOp::RxpOp(Expr &&expr, Rxp::Options opt) : _raw(DynamicRxp{std::move(expr), opt}) {}
Rv<RxpOp>
RxpOp::Cfg_Visitor::operator()(Feature &f)
{
if (IndexFor(STRING) != f.index()) {
return Errata(S_ERROR, R"(Regular expression literal was not a string as required.)");
}
auto &&[rxp, rxp_errata]{Rxp::parse(std::get<IndexFor(STRING)>(f), _rxp_opt)};
if (!rxp_errata.is_ok()) {
rxp_errata.note(R"(While parsing regular expression.)");
return std::move(rxp_errata);
}
_cfg.require_rxp_group_count(rxp.capture_count());
return RxpOp(std::move(rxp));
}
Rv<RxpOp>
RxpOp::Cfg_Visitor::operator()(std::monostate)
{
return Errata(S_ERROR, R"(Literal must be a string)");
}
Rv<RxpOp>
RxpOp::Cfg_Visitor::operator()(Expr::Direct &d)
{
return RxpOp(Expr(std::move(d)), _rxp_opt);
}
Rv<RxpOp>
RxpOp::Cfg_Visitor::operator()(Expr::Composite &comp)
{
return RxpOp(Expr(std::move(comp)), _rxp_opt);
}
Rv<RxpOp>
RxpOp::Cfg_Visitor::operator()(Expr::List &)
{
return Errata(S_ERROR, R"(Literal must be a string)");
}
bool
RxpOp::Apply_Visitor::operator()(std::monostate) const
{
return false;
}
bool
RxpOp::Apply_Visitor::operator()(const Rxp &rxp) const
{
auto result = rxp(_src, _ctx.rxp_working_match_data());
if (result > 0) {
_ctx.rxp_commit_match(_src);
_ctx._remainder.clear();
return true;
}
return false;
}
bool
RxpOp::Apply_Visitor::operator()(DynamicRxp const &dr) const
{
auto f = _ctx.extract(dr._expr);
if (auto text = std::get_if<IndexFor(STRING)>(&f); text != nullptr) {
auto &&[rxp, rxp_errata]{Rxp::parse(*text, dr._opt)};
if (rxp_errata.is_ok()) {
_ctx.rxp_match_require(rxp.capture_count());
return (*this)(rxp); // forward to Rxp overload.
}
}
return false;
}
Rv<RxpOp>
RxpOp::load(Config &cfg, Expr &&expr, Rxp::Options opt)
{
return {std::visit(Cfg_Visitor(cfg, opt), expr._raw)};
}
int
RxpOp::operator()(Context &ctx, swoc::TextView src)
{
return std::visit(Apply_Visitor{ctx, src}, _raw);
}
size_t
RxpOp::capture_count()
{
if (_raw.index() == STATIC) {
return std::get<STATIC>(_raw).capture_count();
}
return 0; // No rxp or indeterminate.
}