| /** @file |
| |
| A brief file description |
| |
| @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. |
| */ |
| |
| #include <array> |
| |
| #include "tscore/ink_platform.h" |
| #include "tscore/ink_thread.h" |
| #include "tscore/ink_memory.h" |
| #include "tscore/Regex.h" |
| |
| #ifdef PCRE_CONFIG_JIT |
| static pcre_jit_stack * |
| get_jit_stack(void *data ATS_UNUSED) |
| { |
| thread_local struct JitStack { |
| JitStack() |
| { |
| jit_stack = pcre_jit_stack_alloc(ats_pagesize(), 1024 * 1024); // 1 page min and 1MB max |
| } |
| ~JitStack() { pcre_jit_stack_free(jit_stack); } |
| |
| pcre_jit_stack *jit_stack = nullptr; |
| } stack; |
| |
| return stack.jit_stack; |
| } |
| #endif |
| |
| Regex::Regex(Regex &&that) noexcept : regex(that.regex), regex_extra(that.regex_extra) |
| { |
| that.regex = nullptr; |
| that.regex_extra = nullptr; |
| } |
| |
| bool |
| Regex::compile(const char *pattern, const unsigned flags) |
| { |
| const char *error; |
| int erroffset; |
| int options = 0; |
| int study_opts = 0; |
| |
| if (regex) { |
| return false; |
| } |
| |
| if (flags & RE_CASE_INSENSITIVE) { |
| options |= PCRE_CASELESS; |
| } |
| |
| if (flags & RE_ANCHORED) { |
| options |= PCRE_ANCHORED; |
| } |
| |
| regex = pcre_compile(pattern, options, &error, &erroffset, nullptr); |
| if (error) { |
| regex = nullptr; |
| return false; |
| } |
| |
| #ifdef PCRE_CONFIG_JIT |
| study_opts |= PCRE_STUDY_JIT_COMPILE; |
| #endif |
| |
| regex_extra = pcre_study(regex, study_opts, &error); |
| |
| #ifdef PCRE_CONFIG_JIT |
| if (regex_extra) { |
| pcre_assign_jit_stack(regex_extra, &get_jit_stack, nullptr); |
| } |
| #endif |
| |
| return true; |
| } |
| |
| int |
| Regex::get_capture_count() |
| { |
| int captures = -1; |
| if (pcre_fullinfo(regex, regex_extra, PCRE_INFO_CAPTURECOUNT, &captures) != 0) { |
| return -1; |
| } |
| |
| return captures; |
| } |
| |
| bool |
| Regex::exec(std::string_view const &str) const |
| { |
| std::array<int, DEFAULT_GROUP_COUNT * 3> ovector = {{0}}; |
| return this->exec(str, ovector.data(), ovector.size()); |
| } |
| |
| bool |
| Regex::exec(std::string_view const &str, int *ovector, int ovecsize) const |
| { |
| int rv; |
| |
| rv = pcre_exec(regex, regex_extra, str.data(), int(str.size()), 0, 0, ovector, ovecsize); |
| return rv > 0; |
| } |
| |
| Regex::~Regex() |
| { |
| if (regex_extra) { |
| #ifdef PCRE_CONFIG_JIT |
| pcre_free_study(regex_extra); |
| #else |
| pcre_free(regex_extra); |
| #endif |
| } |
| if (regex) { |
| pcre_free(regex); |
| } |
| } |
| |
| DFA::~DFA() {} |
| |
| bool |
| DFA::build(std::string_view const &pattern, unsigned flags) |
| { |
| Regex rxp; |
| std::string string{pattern}; |
| |
| if (!(flags & RE_UNANCHORED)) { |
| flags |= RE_ANCHORED; |
| } |
| |
| if (!rxp.compile(string.c_str(), flags)) { |
| return false; |
| } |
| _patterns.emplace_back(std::move(rxp), std::move(string)); |
| return true; |
| } |
| |
| int |
| DFA::compile(std::string_view const &pattern, unsigned flags) |
| { |
| ink_assert(_patterns.empty()); |
| this->build(pattern, flags); |
| return _patterns.size(); |
| } |
| |
| int |
| DFA::compile(std::string_view *patterns, int npatterns, unsigned flags) |
| { |
| _patterns.reserve(npatterns); // try to pre-allocate. |
| for (int i = 0; i < npatterns; ++i) { |
| this->build(patterns[i], flags); |
| } |
| return _patterns.size(); |
| } |
| |
| int |
| DFA::compile(const char **patterns, int npatterns, unsigned flags) |
| { |
| _patterns.reserve(npatterns); // try to pre-allocate. |
| for (int i = 0; i < npatterns; ++i) { |
| this->build(patterns[i], flags); |
| } |
| return _patterns.size(); |
| } |
| |
| int |
| DFA::match(std::string_view const &str) const |
| { |
| for (auto spot = _patterns.begin(), limit = _patterns.end(); spot != limit; ++spot) { |
| if (spot->_re.exec(str)) { |
| return spot - _patterns.begin(); |
| } |
| } |
| |
| return -1; |
| } |