Commit 8d45f5ff authored by Christian Persch's avatar Christian Persch

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>.

gnome-terminal#43
parent 3df8290b
......@@ -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
......
......@@ -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");
......
......@@ -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
......
......@@ -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;
}
......@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment