summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Persch <chpe@src.gnome.org>2018-11-25 23:46:43 +0100
committerChristian Persch <chpe@src.gnome.org>2018-11-25 23:46:43 +0100
commit8d45f5ff950131d1d9724b62628b4e81a8461462 (patch)
tree4f02b40be51d491173e41e1a0561ce1a0de4a830
parent3df8290b4c90d3794ed00cff7f284fbeb6b0ef72 (diff)
downloadvte-8d45f5ff950131d1d9724b62628b4e81a8461462.tar.gz
regex: Add vte_regex_substitute
Add VteRegex API to substitute a string match with a replacement. Based on a patch by Rodolfo Granata <warlock.cc@gmail.com>. https://gitlab.gnome.org/GNOME/gnome-terminal/issues/43
-rw-r--r--doc/reference/vte-sections.txt1
-rw-r--r--src/app/app.cc25
-rw-r--r--src/vte/vteregex.h7
-rw-r--r--src/vteregex.cc67
-rw-r--r--src/vteregexinternal.hh2
5 files changed, 96 insertions, 6 deletions
diff --git a/doc/reference/vte-sections.txt b/doc/reference/vte-sections.txt
index 532c061c..9ab873c1 100644
--- a/doc/reference/vte-sections.txt
+++ b/doc/reference/vte-sections.txt
@@ -166,6 +166,7 @@ vte_regex_unref
vte_regex_new_for_match
vte_regex_new_for_search
vte_regex_jit
+vte_regex_substitute
<SUBSECTION Standard>
VTE_TYPE_REGEX
diff --git a/src/app/app.cc b/src/app/app.cc
index d059b6f0..2f2bf099 100644
--- a/src/app/app.cc
+++ b/src/app/app.cc
@@ -1465,26 +1465,43 @@ vteapp_window_show_context_menu(VteappWindow* window,
}
/* Test extra match API */
+ static const char extra_pattern[] = "(\\d+)\\s*(\\w+)";
char* extra_match = nullptr;
+ char *extra_subst = nullptr;
if (options.use_gregex) {
- auto regex = compile_gregex("\\d+", false, nullptr);
+ auto regex = compile_gregex(extra_pattern, false, nullptr);
vte_terminal_event_check_gregex_simple(window->terminal, event,
&regex, 1,
GRegexMatchFlags(0),
&extra_match);
g_regex_unref(regex);
} else {
- auto regex = compile_regex_for_match("\\d+", false, nullptr);
+ auto regex = compile_regex_for_match(extra_pattern, false, nullptr);
vte_terminal_event_check_regex_simple(window->terminal, event,
&regex, 1, 0,
&extra_match);
+
+ GError *err = nullptr;
+ if (extra_match != nullptr &&
+ (extra_subst = vte_regex_substitute(regex, extra_match, "$2 $1",
+ PCRE2_SUBSTITUTE_EXTENDED |
+ PCRE2_SUBSTITUTE_GLOBAL,
+ &err)) == nullptr) {
+ verbose_printerr("Substitution failed: %s\n", err->message);
+ g_error_free(err);
+ }
+
vte_regex_unref(regex);
}
if (extra_match != nullptr) {
- verbose_print("\\d+ match: %s\n", extra_match);
- g_free(extra_match);
+ if (extra_subst != nullptr)
+ verbose_print("%s match: %s => %s\n", extra_pattern, extra_match, extra_subst);
+ else
+ verbose_print("%s match: %s\n", extra_pattern, extra_match);
}
+ g_free(extra_match);
+ g_free(extra_subst);
}
g_menu_append(menu, "_Paste", "win.paste");
diff --git a/src/vte/vteregex.h b/src/vte/vteregex.h
index c64c1273..f420a1fe 100644
--- a/src/vte/vteregex.h
+++ b/src/vte/vteregex.h
@@ -67,6 +67,13 @@ gboolean vte_regex_jit (VteRegex *regex,
guint32 flags,
GError **error) _VTE_GNUC_NONNULL(1);
+_VTE_PUBLIC
+char *vte_regex_substitute(VteRegex *regex,
+ const char *subject,
+ const char *replacement,
+ guint32 flags,
+ GError **error) _VTE_GNUC_NONNULL(1) _VTE_GNUC_NONNULL(2) _VTE_GNUC_NONNULL(3) G_GNUC_MALLOC;
+
#if GLIB_CHECK_VERSION(2, 44, 0)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(VteRegex, vte_regex_unref)
#endif
diff --git a/src/vteregex.cc b/src/vteregex.cc
index 01ccfb99..102a4537 100644
--- a/src/vteregex.cc
+++ b/src/vteregex.cc
@@ -386,7 +386,7 @@ _vte_regex_has_purpose(VteRegex *regex,
* Returns: the #pcre2_code_8 from @regex
*/
const pcre2_code_8 *
-_vte_regex_get_pcre(VteRegex *regex)
+_vte_regex_get_pcre(VteRegex const* regex)
{
g_return_val_if_fail(regex != NULL, NULL);
@@ -457,3 +457,68 @@ _vte_regex_get_compile_flags(VteRegex *regex)
return r == 0 ? v : 0u;
}
+
+/**
+ * vte_regex_substitute:
+ * @regex: a #VteRegex
+ * @subject: the subject string
+ * @replacement: the replacement string
+ * @flags: PCRE2 match flags
+ * @error: (nullable): return location for a #GError, or %NULL
+ *
+ * See man:pcre2api(3) on pcre2_substitute() for more information.
+ *
+ * Returns: (transfer full): the substituted string, or %NULL
+ * if an error occurred
+ *
+ * Since: 0.56
+ */
+char *
+vte_regex_substitute(VteRegex *regex,
+ const char *subject,
+ const char *replacement,
+ guint32 flags,
+ GError **error)
+{
+ g_return_val_if_fail(regex != nullptr, nullptr);
+ g_return_val_if_fail(subject != nullptr, nullptr);
+ g_return_val_if_fail(replacement != nullptr, nullptr);
+ g_return_val_if_fail (!(flags & PCRE2_SUBSTITUTE_OVERFLOW_LENGTH), nullptr);
+
+ uint8_t outbuf[2048];
+ PCRE2_SIZE outlen = sizeof(outbuf);
+ int r = pcre2_substitute_8(_vte_regex_get_pcre(regex),
+ (PCRE2_SPTR8)subject, PCRE2_ZERO_TERMINATED,
+ 0 /* start offset */,
+ flags | PCRE2_SUBSTITUTE_OVERFLOW_LENGTH,
+ nullptr /* match data */,
+ nullptr /* match context */,
+ (PCRE2_SPTR8)replacement, PCRE2_ZERO_TERMINATED,
+ (PCRE2_UCHAR8*)outbuf, &outlen);
+
+ if (r >= 0)
+ return g_strndup((char*)outbuf, outlen);
+
+ if (r == PCRE2_ERROR_NOMEMORY) {
+ /* The buffer was not large enough; allocated a buffer of the
+ * required size and try again. Note that @outlen as returned
+ * from pcre2_substitute_8() above includes the trailing \0.
+ */
+ uint8_t *outbuf2 = (uint8_t*)g_malloc(outlen);
+ r = pcre2_substitute_8(_vte_regex_get_pcre(regex),
+ (PCRE2_SPTR8)subject, PCRE2_ZERO_TERMINATED,
+ 0 /* start offset */,
+ flags | PCRE2_SUBSTITUTE_OVERFLOW_LENGTH,
+ nullptr /* match data */,
+ nullptr /* match context */,
+ (PCRE2_SPTR8)replacement, PCRE2_ZERO_TERMINATED,
+ (PCRE2_UCHAR8*)outbuf2, &outlen);
+ if (r >= 0)
+ return (char*)outbuf2;
+
+ g_free(outbuf2);
+ }
+
+ set_gerror_from_pcre_error(r, error);
+ return nullptr;
+}
diff --git a/src/vteregexinternal.hh b/src/vteregexinternal.hh
index 21f43f8f..1b4a78fd 100644
--- a/src/vteregexinternal.hh
+++ b/src/vteregexinternal.hh
@@ -29,7 +29,7 @@ gboolean _vte_regex_get_jited(VteRegex *regex);
guint32 _vte_regex_get_compile_flags (VteRegex *regex);
-const pcre2_code_8 *_vte_regex_get_pcre (VteRegex *regex);
+const pcre2_code_8 *_vte_regex_get_pcre (VteRegex const* regex);
/* GRegex translation */
VteRegex *_vte_regex_new_gregex(VteRegexPurpose purpose,