1#include "../include/regex.h"
25 pcre2_match_data* match_data;
50static void pcre2_err_message(
int errcode,
char* buf,
size_t buf_len) {
51 PCRE2_UCHAR8 tmp[256];
52 if (pcre2_get_error_message(errcode, tmp,
sizeof(tmp)) < 0) {
53 snprintf(buf, buf_len,
"PCRE2 error %d (no message available)", errcode);
55 snprintf(buf, buf_len,
"%s", (
const char*)tmp);
69 const PCRE2_SIZE* ov = pcre2_get_ovector_pointer(md);
73 uint32_t total = re->group_count + 1;
79 for (uint32_t i = 0; i < total; i++) {
94 if (pattern == NULL || out == NULL) {
101 PCRE2_SIZE erroffset = 0;
103 pcre2_code* code = pcre2_compile((PCRE2_SPTR8)pattern, PCRE2_ZERO_TERMINATED, (uint32_t)flags, &errcode, &erroffset,
107 if (errbuf != NULL && errbuf_len > 0) {
108 PCRE2_UCHAR8 tmp[256];
109 pcre2_get_error_message(errcode, tmp,
sizeof(tmp));
110 snprintf(errbuf, errbuf_len,
"pattern error at offset %zu: %s", (
size_t)erroffset, (
const char*)tmp);
116 pcre2_jit_compile(code, PCRE2_JIT_COMPLETE);
119 uint32_t group_count = 0;
120 pcre2_pattern_info(code, PCRE2_INFO_CAPTURECOUNT, &group_count);
124 pcre2_code_free(code);
125 if (errbuf != NULL && errbuf_len > 0) {
126 snprintf(errbuf, errbuf_len,
"pattern has %u capture groups; limit is %d", group_count,
133 char* pat_dup = strdup(pattern);
134 if (pat_dup == NULL) {
135 pcre2_code_free(code);
140 regex_t* re = malloc(
sizeof(*re));
143 pcre2_code_free(code);
150 .group_count = group_count,
153 atomic_store(&re->refcount, 1);
161 atomic_fetch_add(&re->refcount, 1);
171 if (atomic_fetch_sub(&re->refcount, 1) == 1) {
173 pcre2_code_free(re->code);
199 if (ctx->match_data == NULL) {
212 pcre2_match_data_free(ctx->match_data);
222 if (re == NULL || ctx == NULL || subject == NULL || match == NULL) {
229 int rc = pcre2_match(re->code, (PCRE2_SPTR8)subject, (PCRE2_SIZE)len, (PCRE2_SIZE)offset, 0 ,
230 ctx->match_data, NULL );
232 if (rc == PCRE2_ERROR_NOMATCH) {
239 fill_match(re, ctx->match_data, rc, match);
244 if (subject == NULL) {
247 return regex_exec(re, ctx, subject, strlen(subject), 0, match);
251 if (re == NULL || ctx == NULL || subject == NULL) {
255 int rc = pcre2_match(re->code, (PCRE2_SPTR8)subject, (PCRE2_SIZE)len, 0, 0, ctx->match_data, NULL);
265 if (re == NULL || ctx == NULL || subject == NULL || out == NULL) {
288 if (iter == NULL || match == NULL) {
291 if (iter->offset > iter->len) {
295 int rc = pcre2_match(iter->re->code, (PCRE2_SPTR8)iter->subject, (PCRE2_SIZE)iter->len, (PCRE2_SIZE)iter->offset, 0,
296 iter->ctx->match_data, NULL);
298 if (rc == PCRE2_ERROR_NOMATCH) {
305 fill_match(iter->re, iter->ctx->match_data, rc, match);
312 if (end == iter->offset) {
313 iter->offset = end + 1;
338 const char* replacement,
char* out_buf,
size_t* out_len, uint32_t pcre2_flags) {
339 if (re == NULL || ctx == NULL || subject == NULL || replacement == NULL || out_buf == NULL || out_len == NULL) {
343 PCRE2_SIZE result_len = (PCRE2_SIZE)*out_len;
345 int rc = pcre2_substitute(re->code, (PCRE2_SPTR8)subject, (PCRE2_SIZE)subject_len, 0 ,
346 pcre2_flags | PCRE2_SUBSTITUTE_EXTENDED, ctx->match_data, NULL ,
347 (PCRE2_SPTR8)replacement, PCRE2_ZERO_TERMINATED, (PCRE2_UCHAR8*)out_buf, &result_len);
349 if (rc == PCRE2_ERROR_NOMATCH || rc == 0) {
352 if (rc == PCRE2_ERROR_NOMEMORY) {
354 *out_len = (size_t)result_len;
362 *out_len = (size_t)result_len;
367 const char* replacement,
char* out_buf,
size_t* out_len) {
368 return sub_impl(re, ctx, subject, subject_len, replacement, out_buf, out_len, 0 );
372 const char* replacement,
char* out_buf,
size_t* out_len) {
373 return sub_impl(re, ctx, subject, subject_len, replacement, out_buf, out_len, PCRE2_SUBSTITUTE_GLOBAL);
384 return re->group_count;
395 if (buf == NULL || buf_len == 0) {
407 msg =
"general error";
410 msg =
"memory allocation failed";
413 msg =
"invalid arguments";
416 msg =
"too many capture groups";
419 msg =
"unknown status code";
422 snprintf(buf, buf_len,
"%s", msg);
void regex_iter_free(regex_iter_t *iter)
regex_t * regex_retain(regex_t *re)
struct regex_ctx_s regex_ctx_t
struct regex_iter_s regex_iter_t
uint32_t regex_group_count(const regex_t *re)
const char * regex_pattern(const regex_t *re)
regex_status_t regex_ctx_create(regex_ctx_t **out)
regex_status_t regex_sub(const regex_t *re, regex_ctx_t *ctx, const char *subject, size_t subject_len, const char *replacement, char *out_buf, size_t *out_len)
void regex_strerror(regex_status_t status, char *buf, size_t buf_len)
regex_status_t regex_compile(const char *pattern, regex_flags_t flags, regex_t **out, char *errbuf, size_t errbuf_len)
regex_status_t regex_match(const regex_t *re, regex_ctx_t *ctx, const char *subject, regex_match_t *match)
regex_status_t regex_iter_next(regex_iter_t *iter, regex_match_t *match)
regex_status_t regex_gsub(const regex_t *re, regex_ctx_t *ctx, const char *subject, size_t subject_len, const char *replacement, char *out_buf, size_t *out_len)
regex_status_t regex_exec(const regex_t *re, regex_ctx_t *ctx, const char *subject, size_t len, size_t offset, regex_match_t *match)
void regex_ctx_free(regex_ctx_t *ctx)
bool regex_is_match(const regex_t *re, regex_ctx_t *ctx, const char *subject, size_t len)
void regex_free(regex_t *re)
regex_status_t regex_iter_init(regex_t *re, regex_ctx_t *ctx, const char *subject, size_t len, regex_iter_t **out)
regex_span_t group[REGEX_MAX_GROUPS]