gnucash stable: Bug 799439 - Duplicate information in description when importing...

John Ralls jralls at code.gnucash.org
Tue Dec 10 18:38:43 EST 2024


Updated	 via  https://github.com/Gnucash/gnucash/commit/6c216877 (commit)
	from  https://github.com/Gnucash/gnucash/commit/f0f875d5 (commit)



commit 6c2168772b2485c6cf15032db1e8f0ef34a1eff4
Author: John Ralls <jralls at ceridwen.us>
Date:   Tue Dec 10 15:30:03 2024 -0800

    Bug 799439 - Duplicate information in description when importing...
    
    CAMT.053.001.02 via aqbanking
    
    Deduplicate the description inputs when joining them by creating a
    variant of gnc_g_list_stringjoin named gnc_g_list_stringjoin_nodups
    that tests each string against the agregate string and adds it only if
    it's not already included. Note that while it uses g_utf8_normalize to
    ensure that non-ascii strings are consistently composed it has to do a
    bytewise comparison with strstr as glib doesn't provide a UTF-8
    equivalent. strnocasestr would work only with ASCII strings so it's
    not suitable.

diff --git a/gnucash/import-export/aqb/gnc-ab-utils.c b/gnucash/import-export/aqb/gnc-ab-utils.c
index 0d7b6e0d8a..e1b1d3a3d9 100644
--- a/gnucash/import-export/aqb/gnc-ab-utils.c
+++ b/gnucash/import-export/aqb/gnc-ab-utils.c
@@ -427,7 +427,7 @@ gnc_ab_description_to_gnc (const AB_TRANSACTION *ab_trans, gboolean is_ofx)
     acc = g_list_prepend (acc, gnc_ab_get_remote_name (ab_trans));
     acc = g_list_prepend (acc, gnc_ab_get_purpose (ab_trans, is_ofx));
     acc = g_list_prepend (acc, ab_ultimate_creditor_debtor_to_gnc (ab_trans, is_ofx));
-    retval = gnc_g_list_stringjoin (acc, "; ");
+    retval = gnc_g_list_stringjoin_nodups (acc, "; ");
 
     g_list_free_full (acc, g_free);
     return retval ? retval : g_strdup (_("Unspecified"));
diff --git a/libgnucash/core-utils/gnc-glib-utils.c b/libgnucash/core-utils/gnc-glib-utils.c
index b2e55af29b..cd837ee55a 100644
--- a/libgnucash/core-utils/gnc-glib-utils.c
+++ b/libgnucash/core-utils/gnc-glib-utils.c
@@ -23,9 +23,11 @@
 
 #include <config.h>
 #include <errno.h>
+#include <mach/arm/boolean.h>
 #include <stdio.h>
 #include <signal.h>
 #include <string.h>
+#include <stdbool.h>
 
 #include "gnc-glib-utils.h"
 
@@ -287,9 +289,25 @@ gnc_g_list_cut(GList **list, GList *cut_point)
     cut_point->prev = NULL;
 }
 
+static bool
+utf8_strstr(char **needle, char *haystack)
+{
+    char *tmp = g_utf8_normalize (*needle, -1, G_NORMALIZE_NFC);
+    if (haystack && *haystack)
+    {
+        char *place = strstr(haystack, tmp);
+        if (place)
+        {
+            g_free (tmp);
+            return false;
+        }
+    }
+    *needle = tmp; //so that haystack is already normalized
+    return true;
+}
 
-gchar *
-gnc_g_list_stringjoin (GList *list_of_strings, const gchar *sep)
+static gchar *
+gnc_g_list_stringjoin_internal (GList *list_of_strings, const gchar *sep, bool testdups)
 {
     gint seplen = sep ? strlen(sep) : 0;
     gint length = -seplen;
@@ -311,14 +329,31 @@ gnc_g_list_stringjoin (GList *list_of_strings, const gchar *sep)
         gchar *str = n->data;
         if (!str || !str[0])
             continue;
-        if (sep && (p != retval))
-            p = g_stpcpy (p, sep);
-        p = g_stpcpy (p, str);
+        if (!testdups || utf8_strstr (&str, retval))
+        {
+            if (sep && (p != retval))
+                p = g_stpcpy (p, sep);
+            p = g_stpcpy (p, str);
+            if (testdups)
+                g_free (str);
+        }
     }
 
     return retval;
 }
 
+gchar *
+gnc_g_list_stringjoin (GList *list_of_strings, const gchar *sep)
+{
+    return gnc_g_list_stringjoin_internal (list_of_strings, sep, false);
+}
+
+gchar *
+gnc_g_list_stringjoin_nodups (GList *list_of_strings, const gchar *sep)
+{
+    return gnc_g_list_stringjoin_internal (list_of_strings, sep, true);
+}
+
 gint
 gnc_list_length_cmp (const GList *list, size_t len)
 {
diff --git a/libgnucash/core-utils/gnc-glib-utils.h b/libgnucash/core-utils/gnc-glib-utils.h
index eb291336bb..a2770aaaf8 100644
--- a/libgnucash/core-utils/gnc-glib-utils.h
+++ b/libgnucash/core-utils/gnc-glib-utils.h
@@ -184,6 +184,19 @@ void gnc_g_list_cut(GList **list, GList *cut_point);
  * caller.
  **/
 gchar * gnc_g_list_stringjoin (GList *list_of_strings, const gchar *sep);
+/**
+ * @brief Like stringjoin but ensures that the string to be added isn't
+ * already part of the return string.
+ *
+ * @param list_of_strings A GList of chars*
+ *
+ * @param sep a separator or NULL
+ *
+ * @return A newly allocated string that has to be g_free'd by the
+ * caller.
+ **/
+gchar * gnc_g_list_stringjoin_nodups (GList *list_of_strings, const gchar *sep);
+
 /**
  * @brief Scans the GList elements the minimum number of iterations
  * required to test it against a specified size. Returns -1, 0 or 1
diff --git a/libgnucash/core-utils/test/test-gnc-glib-utils.c b/libgnucash/core-utils/test/test-gnc-glib-utils.c
index 43a74f1c4e..2f87d80f96 100644
--- a/libgnucash/core-utils/test/test-gnc-glib-utils.c
+++ b/libgnucash/core-utils/test/test-gnc-glib-utils.c
@@ -115,6 +115,24 @@ test_g_list_stringjoin (gconstpointer data)
     g_list_free (test);
 }
 
+static void
+test_g_list_stringjoin_nodups (gconstpointer data)
+{
+    GList *test = NULL;
+    gchar *ret;
+
+    test = g_list_prepend (test, "one");
+    test = g_list_prepend (test, "two");
+    test = g_list_prepend (test, "two");
+    test = g_list_prepend (test, "three");
+    test = g_list_prepend (test, "one:two");
+    test = g_list_prepend (test, "four");
+    test = g_list_reverse (test);
+    ret = gnc_g_list_stringjoin_nodups (test, ":");
+    g_assert_cmpstr (ret, ==, "one:two:three:four");
+    g_free (ret);
+}
+
 static void
 test_gnc_list_length (gconstpointer data)
 {
@@ -146,6 +164,7 @@ main (int argc, char *argv[])
     g_test_add_data_func ("/core-utils/gnc_utf8_strip_invalid_and_controls invalid utf8", (gconstpointer)invalid_utf8, test_gnc_utf8_strip_invalid_and_controls);
     g_test_add_data_func ("/core-utils/gnc_utf8_strip_invalid_and_controls control chars", (gconstpointer)controls, test_gnc_utf8_strip_invalid_and_controls);
     g_test_add_data_func ("/core-utils/gnc_g_list_stringjoin", NULL, test_g_list_stringjoin);
+    g_test_add_data_func ("/core-utils/gnc_g_list_stringjoin_nodups", NULL, test_g_list_stringjoin_nodups);
     g_test_add_data_func ("/core-utils/gnc_list_length", NULL, test_gnc_list_length);
 
     return g_test_run();



Summary of changes:
 gnucash/import-export/aqb/gnc-ab-utils.c         |  2 +-
 libgnucash/core-utils/gnc-glib-utils.c           | 45 +++++++++++++++++++++---
 libgnucash/core-utils/gnc-glib-utils.h           | 13 +++++++
 libgnucash/core-utils/test/test-gnc-glib-utils.c | 19 ++++++++++
 4 files changed, 73 insertions(+), 6 deletions(-)



More information about the gnucash-changes mailing list