[vte] regex: Add vte_regex_substitute



commit 8d45f5ff950131d1d9724b62628b4e81a8461462
Author: Christian Persch <chpe src gnome org>
Date:   Sun Nov 25 23:46:43 2018 +0100

    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

 doc/reference/vte-sections.txt |  1 +
 src/app/app.cc                 | 25 +++++++++++++---
 src/vte/vteregex.h             |  7 +++++
 src/vteregex.cc                | 67 +++++++++++++++++++++++++++++++++++++++++-
 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,
                                                                &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,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]