blob: 9b6840600ea443bf2ec4f9596f89ee57025f8c03 [file] [log] [blame]
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed 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 "dctv.h"
#include "fmt.h"
#include "pcreutil.h"
#include "pyerrfmt.h"
#include "pythread.h"
#include "pyutil.h"
namespace dctv {
static
void*
malloc_for_pcre2(size_t sz, void*) noexcept
{
try {
return _do_py_malloc(sz);
} catch (const std::bad_alloc&) {
return nullptr;
}
}
static
void
free_for_pcre2(void* mem, void*) noexcept
{
_do_py_free(mem);
}
unique_pcre2_code
compile_pcre2_pattern(std::string_view pattern,
uint32_t options)
{
unique_pcre2_general_context general_context(
pcre2_general_context_create(
malloc_for_pcre2,
free_for_pcre2,
/*memory_data=*/nullptr));
if (!general_context)
throw std::bad_alloc();
unique_pcre2_compile_context compile_context(
pcre2_compile_context_create(general_context.get()));
if (!compile_context)
throw std::bad_alloc();
int errorcode;
size_t erroroffset;
auto cpat = unique_pcre2_code(
pcre2_compile(
reinterpret_cast<PCRE2_SPTR>(pattern.data()),
pattern.size(),
options,
&errorcode,
&erroroffset,
compile_context.get()));
if (!cpat)
throw_pcre2_error_nogil(errorcode,
"pcre2_compile",
&pattern,
&erroroffset);
return cpat;
}
unique_pcre2_match_data
make_pcre2_match_data(const pcre2_code* cpat)
{
unique_pcre2_match_data match_data(
pcre2_match_data_create_from_pattern(
cpat,
/*general_context=*/nullptr));
if (!match_data)
throw std::bad_alloc();
return match_data;
}
void
jit_compile_pcre2(pcre2_code* cpat, uint32_t options)
{
if (int rc = pcre2_jit_compile(cpat, options); rc)
throw_pcre2_error_nogil(rc, "pcre2_jit_compile");
}
void
throw_pcre2_error_nogil(int rc,
std::string_view api,
const std::string_view* pattern,
const size_t* erroroffset)
{
with_gil_acquired([&] {
// Documentation indicates that 120 characters is "ample". If it's
// not, we'll just get PCRE2_ERROR_NOMEMORY and a truncated (but
// still NUL-terminated) error message.
PCRE2_UCHAR buf[120];
int msglen =
pcre2_get_error_message(rc, buf, sizeof (buf));
if (msglen == PCRE2_ERROR_NOMEMORY)
msglen = sizeof (buf) - 1;
if (msglen < 0)
throw_pyerr_fmt(PyExc_SystemError,
"%s: error getting PCRE error string: %d",
api, msglen);
String suffix;
if (pattern && erroroffset)
suffix = fmt(" at %d (%s) in %s",
*erroroffset,
repr(pattern->substr(*erroroffset, 10)),
repr(*pattern));
throw_pyerr_fmt(
PyExc_ValueError,
"%s: %s%s",
api,
std::string_view(reinterpret_cast<char*>(buf), msglen),
suffix);
});
DCTV_UNREACHABLE;
}
} // namespace dctv