[gtksourceview/wip/chergert/pcre2] pcre2: start on pcre2 implementation
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/chergert/pcre2] pcre2: start on pcre2 implementation
- Date: Sat, 26 Sep 2020 00:09:07 +0000 (UTC)
commit e911ef08dda0270f69ac88838e0996b724a3802e
Author: Christian Hergert <chergert redhat com>
Date: Fri Sep 25 10:23:18 2020 -0700
pcre2: start on pcre2 implementation
gtksourceview/implregex-private.h | 4 +
gtksourceview/implregex.c | 414 +++++++++++++++++++++++++++++++-------
2 files changed, 343 insertions(+), 75 deletions(-)
---
diff --git a/gtksourceview/implregex-private.h b/gtksourceview/implregex-private.h
index da52474e..785d060a 100644
--- a/gtksourceview/implregex-private.h
+++ b/gtksourceview/implregex-private.h
@@ -41,6 +41,7 @@ gboolean impl_regex_match (const ImplRegex *regex,
const char *string,
GRegexMatchFlags match_options,
ImplMatchInfo **match_info);
+ImplRegex *impl_regex_ref (ImplRegex *regex);
void impl_regex_unref (ImplRegex *regex);
void impl_match_info_free (ImplMatchInfo *match_info);
char *impl_match_info_fetch (const ImplMatchInfo *match_info,
@@ -70,6 +71,9 @@ gboolean impl_match_info_fetch_named_pos (const ImplMatchInfo *match_info,
const char *name,
int *start_pos,
int *end_pos);
+gboolean impl_match_info_matches (const ImplMatchInfo *match_info);
+gboolean impl_match_info_next (ImplMatchInfo *match_info,
+ GError **error);
const char *impl_regex_get_pattern (const ImplRegex *regex);
G_END_DECLS
diff --git a/gtksourceview/implregex.c b/gtksourceview/implregex.c
index 56a12799..2dee6de8 100644
--- a/gtksourceview/implregex.c
+++ b/gtksourceview/implregex.c
@@ -21,27 +21,49 @@
#include "config.h"
+#define PCRE2_CODE_UNIT_WIDTH 8
+
+#include <pcre2.h>
+#include <string.h>
+
#include "implregex-private.h"
+#define IS_PCRE_ERROR(ret) ((ret) < PCRE2_ERROR_NOMATCH && (ret) != PCRE2_ERROR_PARTIAL)
+
struct _ImplRegex
{
- int ref_count;
- char *pattern;
- GRegex *re;
+ int ref_count;
+ char *pattern;
+ pcre2_code *code;
+ GRegexMatchFlags match_options;
+ PCRE2_SPTR name_table;
+ int name_count;
+ int name_entry_size;
};
struct _ImplMatchInfo
{
- GMatchInfo *match_info;
+ ImplRegex *regex;
+ const char *string;
+ gsize string_len;
+ pcre2_match_data *match_data;
+ gsize flags;
+ int n_matches;
+ gssize prev_begin;
+ gssize prev_end;
};
-#if 0
static void
set_regex_error (GError **error,
int errnum)
{
guchar errstr[128];
+ if (error == NULL)
+ {
+ return;
+ }
+
pcre2_get_error_message (errnum, errstr, sizeof errstr - 1);
errstr[sizeof errstr - 1] = 0;
@@ -50,15 +72,18 @@ set_regex_error (GError **error,
G_REGEX_ERROR_COMPILE,
(const gchar *)errstr);
}
-#endif
static ImplMatchInfo *
-impl_match_info_new (const ImplRegex *regex)
+impl_match_info_new (ImplRegex *regex)
{
ImplMatchInfo *match_info;
match_info = g_slice_new0 (ImplMatchInfo);
- match_info->match_info = NULL;
+ match_info->regex = impl_regex_ref (regex);
+ match_info->match_data = pcre2_match_data_create_from_pattern (regex->code, NULL);
+ match_info->prev_begin = -1;
+ match_info->prev_end = -1;
+ match_info->n_matches = -1;
return match_info;
}
@@ -69,22 +94,50 @@ impl_regex_new (const char *pattern,
GRegexMatchFlags match_options,
GError **error)
{
- GRegex *re;
+ pcre2_code *code;
ImplRegex *regex;
+ PCRE2_SIZE erroffset;
+ gsize flags = PCRE2_UTF | PCRE2_NO_UTF_CHECK | PCRE2_ZERO_TERMINATED;
+ int errnumber;
g_return_val_if_fail (pattern != NULL, NULL);
- re = g_regex_new (pattern, compile_options, match_options, error);
+ if (compile_options & G_REGEX_CASELESS)
+ flags |= PCRE2_CASELESS;
+
+ if (compile_options & G_REGEX_NEWLINE_LF)
+ flags |= PCRE2_NEWLINE_LF;
+
+ code = pcre2_compile ((PCRE2_SPTR)pattern,
+ flags,
+ 0,
+ &errnumber,
+ &erroffset,
+ NULL);
- if (re == NULL)
+ if (code == NULL)
{
+ set_regex_error (error, errnumber);
return NULL;
}
regex = g_slice_new0 (ImplRegex);
regex->ref_count = 1;
regex->pattern = g_strdup (pattern);
- regex->re = re;
+ regex->match_options = match_options;
+ regex->code = code;
+
+ (void)pcre2_pattern_info (code, PCRE2_INFO_NAMECOUNT, ®ex->name_count);
+
+ if (regex->name_count > 0)
+ {
+ (void)pcre2_pattern_info (code,
+ PCRE2_INFO_NAMEENTRYSIZE,
+ ®ex->name_entry_size);
+ (void)pcre2_pattern_info (code,
+ PCRE2_INFO_NAMETABLE,
+ ®ex->name_table);
+ }
return regex;
}
@@ -97,6 +150,17 @@ impl_regex_get_pattern (const ImplRegex *regex)
return regex->pattern;
}
+ImplRegex *
+impl_regex_ref (ImplRegex *regex)
+{
+ g_return_val_if_fail (regex != NULL, NULL);
+ g_return_val_if_fail (regex->ref_count > 0, NULL);
+
+ regex->ref_count++;
+
+ return regex;
+}
+
void
impl_regex_unref (ImplRegex *regex)
{
@@ -108,7 +172,7 @@ impl_regex_unref (ImplRegex *regex)
if (regex->ref_count == 0)
{
g_clear_pointer (®ex->pattern, g_free);
- g_clear_pointer (®ex->re, g_regex_unref);
+ g_clear_pointer (®ex->code, pcre2_code_free);
g_slice_free (ImplRegex, regex);
}
}
@@ -116,8 +180,12 @@ impl_regex_unref (ImplRegex *regex)
void
impl_match_info_free (ImplMatchInfo *match_info)
{
- g_clear_pointer (&match_info->match_info, g_match_info_free);
- g_slice_free (ImplMatchInfo, match_info);
+ if (match_info != NULL)
+ {
+ g_clear_pointer (&match_info->match_data, pcre2_match_data_free);
+ g_clear_pointer (&match_info->regex, impl_regex_unref);
+ g_slice_free (ImplMatchInfo, match_info);
+ }
}
gboolean
@@ -126,52 +194,60 @@ impl_regex_match (const ImplRegex *regex,
GRegexMatchFlags match_options,
ImplMatchInfo **match_info)
{
+ gboolean ret;
+
g_return_val_if_fail (regex != NULL, FALSE);
- g_return_val_if_fail (regex->re != NULL, FALSE);
+ g_return_val_if_fail (regex->code != NULL, FALSE);
- if (match_info != NULL)
- {
- *match_info = impl_match_info_new (regex);
- }
+ ret = impl_regex_match_full (regex,
+ string,
+ strlen (string),
+ 0,
+ match_options,
+ match_info,
+ NULL);
- return g_regex_match (regex->re,
- string,
- match_options,
- match_info ? &(*match_info)->match_info : NULL);
+ return ret;
}
char *
impl_match_info_fetch (const ImplMatchInfo *match_info,
int match_num)
{
+ char *ret;
+ int begin = 0;
+ int end = 0;
+
g_return_val_if_fail (match_info != NULL, NULL);
- return g_match_info_fetch (match_info->match_info, match_num);
+ if (match_info->string == NULL ||
+ !impl_match_info_fetch_pos (match_info, match_num, &begin, &end) ||
+ begin < 0 ||
+ end < 0)
+ ret = g_strdup ("");
+ else
+ ret = g_strndup (match_info->string + begin, end - begin);
+
+ return ret;
}
char *
impl_match_info_fetch_named (const ImplMatchInfo *match_info,
const char *name)
{
+ char *ret;
+ int begin;
+ int end;
+
g_return_val_if_fail (match_info != NULL, NULL);
- return g_match_info_fetch_named (match_info->match_info, name);
-}
+ if (match_info->string == NULL ||
+ !impl_match_info_fetch_named_pos (match_info, name, &begin, &end))
+ ret = g_strdup ("");
+ else
+ ret = g_strndup (match_info->string + begin, end - begin);
-static gboolean
-wrapper_eval (const GMatchInfo *match_info,
- GString *result,
- gpointer user_data)
-{
- struct {
- ImplRegexEvalCallback callback;
- gpointer user_data;
- } *wrapper = user_data;
- ImplMatchInfo wrapped = {
- .match_info = (GMatchInfo *)match_info,
- };
-
- return wrapper->callback (&wrapped, result, wrapper->user_data);
+ return ret;
}
char *
@@ -184,25 +260,70 @@ impl_regex_replace_eval (const ImplRegex *regex,
gpointer user_data,
GError **error)
{
- struct {
- ImplRegexEvalCallback callback;
- gpointer user_data;
- } wrapper;
+ ImplMatchInfo *match_info;
+ GString *out_string;
+ gboolean done;
+ int str_pos;
g_return_val_if_fail (regex != NULL, NULL);
- g_return_val_if_fail (regex->re != NULL, NULL);
+ g_return_val_if_fail (regex->code != NULL, NULL);
- wrapper.callback = eval;
- wrapper.user_data = user_data;
+ if (string_len < 0)
+ {
+ string_len = strlen (string);
+ }
- return g_regex_replace_eval (regex->re,
- string,
- string_len,
- start_position,
- match_options,
- wrapper_eval,
- &wrapper,
- error);
+ if (start_position < 0)
+ {
+ start_position = 0;
+ }
+
+ match_info = NULL;
+
+ if (!impl_regex_match_full (regex,
+ string,
+ string_len,
+ start_position,
+ match_options,
+ &match_info,
+ error))
+ {
+ impl_match_info_free (match_info);
+ return g_strndup (string, string_len);
+ }
+
+ g_assert (match_info != NULL);
+ g_assert (match_info->n_matches > 0);
+
+ str_pos = 0;
+ out_string = g_string_sized_new (string_len);
+ done = FALSE;
+
+ while (!done && impl_match_info_matches (match_info))
+ {
+ g_assert (match_info->prev_begin >= 0);
+ g_assert (match_info->prev_end >= 0);
+
+ g_string_append_len (out_string,
+ string + str_pos,
+ match_info->prev_begin - str_pos);
+ str_pos = match_info->prev_end;
+
+ done = eval (match_info, out_string, user_data);
+
+ if (!impl_match_info_next (match_info, NULL))
+ {
+ break;
+ }
+ }
+
+ g_string_append_len (out_string,
+ string + str_pos,
+ string_len - str_pos);
+
+ impl_match_info_free (match_info);
+
+ return g_string_free (out_string, FALSE);
}
gboolean
@@ -214,28 +335,43 @@ impl_regex_match_full (const ImplRegex *regex,
ImplMatchInfo **match_info,
GError **error)
{
- GMatchInfo *wrapped = NULL;
- gboolean ret;
+ ImplMatchInfo *fallback = NULL;
+ gsize flags = PCRE2_NO_UTF_CHECK;
+ gboolean ret = FALSE;
g_return_val_if_fail (regex != NULL, FALSE);
- g_return_val_if_fail (regex->re != NULL, FALSE);
+ g_return_val_if_fail (regex->code != NULL, FALSE);
+ g_return_val_if_fail (start_position >= 0, FALSE);
+ g_return_val_if_fail (match_options == 0, FALSE);
- ret = g_regex_match_full (regex->re,
- string,
- string_len,
- start_position,
- match_options,
- &wrapped,
- error);
+ if (match_info == NULL)
+ {
+ match_info = &fallback;
+ }
- if (match_info != NULL)
+ if (string_len < 0)
{
- *match_info = g_slice_new0 (ImplMatchInfo);
- (*match_info)->match_info = wrapped;
+ string_len = strlen (string);
}
- else
+
+ *match_info = impl_match_info_new ((ImplRegex *)regex);
+
+ if ((match_options | regex->match_options) & G_REGEX_ANCHORED)
+ {
+ flags |= PCRE2_ANCHORED;
+ }
+
+ (*match_info)->flags = flags;
+ (*match_info)->string = string;
+ (*match_info)->string_len = string_len;
+ (*match_info)->prev_begin = start_position;
+ (*match_info)->prev_end = start_position;
+
+ ret = impl_match_info_next (*match_info, error);
+
+ if (fallback != NULL)
{
- g_match_info_free (wrapped);
+ impl_match_info_free (fallback);
}
return ret;
@@ -247,10 +383,31 @@ impl_match_info_fetch_pos (const ImplMatchInfo *match_info,
int *start_pos,
int *end_pos)
{
+ PCRE2_SIZE *ovector;
+ int real_start_pos;
+ int real_end_pos;
+
g_return_val_if_fail (match_info != NULL, FALSE);
- g_return_val_if_fail (match_info->match_info != NULL, FALSE);
+ g_return_val_if_fail (match_info->match_data != NULL, FALSE);
+ g_return_val_if_fail (match_num >= 0, FALSE);
+
+ if (match_num >= match_info->n_matches)
+ {
+ return FALSE;
+ }
+
+ ovector = pcre2_get_ovector_pointer (match_info->match_data);
+
+ real_start_pos = ovector[2*match_num];
+ real_end_pos = ovector[2*match_num+1];
- return g_match_info_fetch_pos (match_info->match_info, match_num, start_pos, end_pos);
+ if (start_pos != NULL)
+ *start_pos = real_start_pos;
+
+ if (end_pos != NULL)
+ *end_pos = real_end_pos;
+
+ return TRUE;
}
gboolean
@@ -258,9 +415,116 @@ impl_match_info_fetch_named_pos (const ImplMatchInfo *match_info,
const char *name,
int *start_pos,
int *end_pos)
+{
+ PCRE2_SPTR tabptr;
+
+ g_return_val_if_fail (match_info != NULL, FALSE);
+ g_return_val_if_fail (match_info->match_data != NULL, FALSE);
+ g_return_val_if_fail (match_info->regex != NULL, FALSE);
+ g_return_val_if_fail (start_pos != NULL, FALSE);
+ g_return_val_if_fail (end_pos != NULL, FALSE);
+
+ tabptr = match_info->regex->name_table;
+
+ for (int i = 0; i < match_info->regex->name_count; i++)
+ {
+ int n = (tabptr[0] << 8) | tabptr[1];
+
+ if (g_strcmp0 (name, (const char *)(tabptr+2)) == 0)
+ {
+ return impl_match_info_fetch_pos (match_info, n, start_pos, end_pos);
+ }
+
+ tabptr += match_info->regex->name_entry_size;
+ }
+
+ *start_pos = -1;
+ *end_pos = -1;
+
+ return FALSE;
+}
+
+gboolean
+impl_match_info_matches (const ImplMatchInfo *match_info)
{
g_return_val_if_fail (match_info != NULL, FALSE);
- g_return_val_if_fail (match_info->match_info != NULL, FALSE);
- return g_match_info_fetch_named_pos (match_info->match_info, name, start_pos, end_pos);
+ return match_info->n_matches > 0;
+}
+
+gboolean
+impl_match_info_next (ImplMatchInfo *match_info,
+ GError **error)
+{
+ PCRE2_SIZE *ovector;
+ gssize prev_begin;
+ gssize prev_end;
+ int rc;
+
+ g_return_val_if_fail (match_info != NULL, FALSE);
+ g_return_val_if_fail (match_info->regex != NULL, FALSE);
+
+ prev_begin = match_info->prev_begin;
+ prev_end = match_info->prev_end;
+
+ if (prev_end > match_info->string_len)
+ {
+ goto nomatch;
+ }
+
+ rc = pcre2_match (match_info->regex->code,
+ (PCRE2_SPTR)match_info->string,
+ (PCRE2_SIZE)match_info->string_len,
+ prev_end,
+ match_info->flags,
+ match_info->match_data,
+ NULL);
+
+ if (IS_PCRE_ERROR (rc))
+ {
+ set_regex_error (error, rc);
+ return FALSE;
+ }
+
+ ovector = pcre2_get_ovector_pointer (match_info->match_data);
+
+ if (match_info->prev_end == ovector[1])
+ {
+ const char *next = g_utf8_next_char (match_info->string + prev_end);
+
+ match_info->prev_end = next - match_info->string;
+ match_info->prev_begin = match_info->prev_end;
+ }
+ else
+ {
+ match_info->prev_begin = ovector[0];
+ match_info->prev_end = ovector[1];
+ }
+
+ if (rc > 0)
+ {
+ match_info->n_matches = rc;
+
+ /* see bug #515944: http://bugzilla.gnome.org/show_bug.cgi?id=515944 */
+ if (prev_begin == match_info->prev_begin &&
+ prev_end == match_info->prev_end)
+ {
+ /* ignore this match and search the next one */
+ return impl_match_info_next (match_info, error);
+ }
+ }
+ else
+ {
+ goto nomatch;
+ }
+
+ return TRUE;
+
+nomatch:
+ match_info->n_matches = PCRE2_ERROR_NOMATCH;
+ match_info->prev_begin = -1;
+ match_info->prev_end = -1;
+ set_regex_error (error, PCRE2_ERROR_NOMATCH);
+
+ return FALSE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]