From b6373ad8f4b1d325bafda41277088404570640d1 Mon Sep 17 00:00:00 2001
From: ppitu <piotr.chmura.1998@gmail.com>
Date: Tue, 28 Jun 2022 21:08:07 +0000
Subject: [PATCH] Bulk Renamer: Allow multiple matches when using regex (Issue
 #230)

When using 'Search & Replace' with regular expression, only the first match was found and replaced. With this patch, all patterns matching the expression will be found and replaced.

MR !235
---
 .../thunar-sbr/thunar-sbr-replace-renamer.c   | 168 +++++++++---------
 1 file changed, 85 insertions(+), 83 deletions(-)

diff --git a/plugins/thunar-sbr/thunar-sbr-replace-renamer.c b/plugins/thunar-sbr/thunar-sbr-replace-renamer.c
index 6bb33dc62..fbf5fbef5 100644
--- a/plugins/thunar-sbr/thunar-sbr-replace-renamer.c
+++ b/plugins/thunar-sbr/thunar-sbr-replace-renamer.c
@@ -454,107 +454,109 @@ thunar_sbr_replace_renamer_pcre_exec (ThunarSbrReplaceRenamer *replace_renamer,
   gint        *ovec;
   gint         olen;
   gint         rc;
+  gint         index_match;
+  gint         first_index_after_match = 0;
 
   /* guess an initial ovec size */
   olen = (replace_renamer->pcre_capture_count + 10) * 3;
   ovec = g_new0 (gint, olen);
 
-  /* try to match the subject (increasing ovec on-demand) */
-  for (rc = 0; rc <= 0; )
-    {
-      /* try to exec, will return 0 if the ovec is too small */
-      rc = pcre_exec (replace_renamer->pcre_pattern, NULL, subject, strlen (subject), 0, PCRE_NOTEMPTY, ovec, olen);
-      if (G_UNLIKELY (rc < 0))
-        {
-          /* no match or error */
-          g_free (ovec);
-          return g_strdup (subject);
-        }
-      else if (rc == 0)
-        {
-          /* ovec too small, try to increase */
-          olen += 18;
-          ovec = g_realloc (ovec, olen * sizeof (gint));
-        }
-    }
-
   /* allocate a string for the result */
   result = g_string_sized_new (32);
 
-  /* append the text before the match */
-  g_string_append_len (result, subject, ovec[0]);
+  /* go through string */
+  while ((size_t) first_index_after_match < strlen (subject))
+  {
+    /* if rc <= 0 we have no match any more */
+    rc = pcre_exec (replace_renamer->pcre_pattern, NULL, subject, strlen (subject), first_index_after_match, PCRE_NOTEMPTY, ovec, olen);
+    if (rc <= 0)
+      break;
+
+    index_match = ovec[0];
 
-  /* apply the replacement */
-  for (r = replace_renamer->replacement; *r != '\0'; r = g_utf8_next_char (r))
+    /* append the subject text between the matches */
+    for (gint j = first_index_after_match; j < index_match; j++)
     {
-      if (G_UNLIKELY ((r[0] == '\\' || r[0] == '$') && r[1] != '\0'))
-        {
-          /* skip the first char ($ or \) */
-          r += 1;
+      g_string_append_c (result, subject[j]);
+    }
 
-          /* default to no subst */
-          first = 0;
-          second = 0;
+    /* over[1] is the first index after a match */
+    first_index_after_match = ovec[1];
 
-          /* check the char after the \ or $ */
-          if (r[0] == '+' && rc > 1)
-            {
-              /* \+ and $+ is replaced with the last subpattern */
-              first = ovec[(rc - 1) * 2];
-              second = ovec[(rc - 1) * 2 + 1];
-            }
-          else if (r[0] == '&')
-            {
-              /* \& and $& is replaced with the first subpattern (the whole match) */
-              first = ovec[0];
-              second = ovec[1];
-            }
-          else if (r[0] == '`')
-            {
-              /* \` and $` is replaced with the text before the whole match */
-              first = 0;
-              second = ovec[0];
-            }
-          else if (r[0] == '\'')
-            {
-              /* \' and $' is replaced with the text after the whole match */
-              first = ovec[1];
-              second = strlen (subject) - 1;
-            }
-          else if (g_ascii_isdigit (r[0]))
-            {
-              /* \<num> and $<num> is replaced with the <num>th subpattern */
-              idx = (r[0] - '0');
-              if (G_LIKELY (idx >= 0 && idx < rc))
-                {
-                  first = ovec[2 * idx];
-                  second = ovec[2 * idx + 1];
-                }
-            }
-          else if (r[-1] == r[0])
-            {
-              /* just add the $ or \ char */
-              g_string_append_c (result, r[0]);
-              continue;
-            }
-          else
-            {
-              /* just ignore the $ or \ char */
-              continue;
-            }
+    for (r = replace_renamer->replacement; *r != '\0'; r = g_utf8_next_char (r))
+    {
+      if (G_UNLIKELY ((r[0] == '\\' || r[0] == '$') && r[1] != '\0'))
+      {
+        /* skip the first char ($ or \) */
+        r += 1;
+
+        /* default to no subst */
+        first = 0;
+        second = 0;
 
-          /* substitute the string */
-          g_string_append_len (result, subject + first, second - first);
+        /* check the char after the \ or $ */
+        if (r[0] == '+' && rc > 1)
+        {
+          /* \+ and $+ is replaced with the last subpattern */
+          first = ovec[(rc - 1) * 2];
+          second = ovec[(rc - 1) * 2 + 1];
         }
-      else
+        else if (r[0] == '&')
+        {
+          /* \& and $& is replaced with the first subpattern (the whole match) */
+          first = ovec[0];
+          second = ovec[1];
+        }
+        else if (r[0] == '`')
         {
-          /* just append the unichar */
-          g_string_append_unichar (result, g_utf8_get_char (r));
+          /* \` and $` is replaced with the text before the whole match */
+          first = 0;
+          second = ovec[0];
         }
+        else if (r[0] == '\'')
+        {
+          /* \' and $' is replaced with the text after the whole match */
+          first = ovec[1];
+          second = strlen (subject) - 1;
+        }
+        else if (g_ascii_isdigit (r[0]))
+        {
+          /* \<num> and $<num> is replaced with the <num>th subpattern */
+          idx = (r[0] - '0');
+          if (G_LIKELY (idx >= 0 && idx < rc))
+          {
+            first = ovec[2 * idx];
+            second = ovec[2 * idx + 1];
+          }
+        }
+        else if (r[-1] == r[0])
+        {
+          /* just add the $ or \ char */
+          g_string_append_c (result, r[0]);
+          continue;
+        }
+        else
+        {
+          /* just ignore the $ or \ char */
+          continue;
+        }
+
+        /* substitute the string */
+        g_string_append_len (result, subject + first, second - first);
+      }
+      else
+      {
+        /* just append the unichar */
+        g_string_append_unichar (result, g_utf8_get_char (r));
+      }
     }
+  }
 
-  /* append the text after the match */
-  g_string_append (result, subject + ovec[1]);
+  /* append rest of subject string */
+  for (size_t i = first_index_after_match; i < strlen (subject); i++)
+    {
+      g_string_append_c (result, subject[i]);
+    }
 
   /* release the output vector */
   g_free (ovec);
-- 
GitLab