diff options
author | Christian Persch <chpe@src.gnome.org> | 2018-11-25 23:46:43 +0100 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2018-11-25 23:46:43 +0100 |
commit | 8d45f5ff950131d1d9724b62628b4e81a8461462 (patch) | |
tree | 4f02b40be51d491173e41e1a0561ce1a0de4a830 | |
parent | 3df8290b4c90d3794ed00cff7f284fbeb6b0ef72 (diff) | |
download | vte-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.txt | 1 | ||||
-rw-r--r-- | src/app/app.cc | 25 | ||||
-rw-r--r-- | src/vte/vteregex.h | 7 | ||||
-rw-r--r-- | src/vteregex.cc | 67 | ||||
-rw-r--r-- | src/vteregexinternal.hh | 2 |
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, ®ex, 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, ®ex, 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, |