gnucash master: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Fri Mar 3 15:00:55 EST 2023


Updated	 via  https://github.com/Gnucash/gnucash/commit/4fab9f82 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/bbfa3787 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/af02dae2 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/76014f18 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/3d381eb6 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/50f998fa (commit)
	 via  https://github.com/Gnucash/gnucash/commit/c9dc7197 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/57fcaabd (commit)
	from  https://github.com/Gnucash/gnucash/commit/4d0aa8f2 (commit)



commit 4fab9f8284bfe328acf6b78f6e0277bca2fec9b0
Merge: 4d0aa8f24 bbfa37878
Author: John Ralls <jralls at ceridwen.us>
Date:   Fri Mar 3 11:54:43 2023 -0800

    Merge Chris Lam's 'maint-static-string' into master.


commit bbfa378783abd382c04ea8ae7079a7190e199bde
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Mar 2 17:03:39 2023 -0800

    Don't crash and do pass tests.

diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 7846db148..a599f158e 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -2481,7 +2481,7 @@ set_kvp_string_path (Account *acc, std::vector<std::string> const & path,
     g_return_if_fail(GNC_IS_ACCOUNT(acc));
 
     xaccAccountBeginEdit(acc);
-    if (value)
+    if (value && *value)
     {
         GValue v = G_VALUE_INIT;
         g_value_init (&v, G_TYPE_STRING);
@@ -2510,7 +2510,7 @@ get_kvp_string_path (const Account *acc, std::vector<std::string> const & path,
     *v = G_VALUE_INIT;
     if (acc == NULL) return NULL; // how to check path is valid??
     qof_instance_get_path_kvp (QOF_INSTANCE (acc), v, path);
-    return G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (v) : NULL;
+    return G_VALUE_HOLDS_STRING (v) ? g_value_get_string (v) : NULL;
 }
 
 static const char*
diff --git a/libgnucash/engine/test/utest-Account.cpp b/libgnucash/engine/test/utest-Account.cpp
index 6f380ee8b..639c2b5d3 100644
--- a/libgnucash/engine/test/utest-Account.cpp
+++ b/libgnucash/engine/test/utest-Account.cpp
@@ -19,6 +19,7 @@
  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
  * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
  ********************************************************************/
+#include <cstddef>
 #include <glib.h>
 
 #include <config.h>
@@ -1153,7 +1154,7 @@ test_gnc_account_kvp_setters_getters (Fixture *fixture, gconstpointer pData)
     g_assert_cmpstr (xaccAccountGetTaxUSCode (account), ==, "red");
 
     xaccAccountSetTaxUSCode (account, "");
-    g_assert_cmpstr (xaccAccountGetTaxUSCode (account), ==, "");
+    g_assert_cmpstr (xaccAccountGetTaxUSCode (account), ==, nullptr);
 
     xaccAccountSetTaxUSCode (account, "  ");
     g_assert_cmpstr (xaccAccountGetTaxUSCode (account), ==, "  ");
@@ -1171,7 +1172,7 @@ test_gnc_account_kvp_setters_getters (Fixture *fixture, gconstpointer pData)
     g_assert_cmpstr (xaccAccountGetTaxUSPayerNameSource (account), ==, "red");
 
     xaccAccountSetTaxUSPayerNameSource (account, "");
-    g_assert_cmpstr (xaccAccountGetTaxUSPayerNameSource (account), ==, "");
+    g_assert_cmpstr (xaccAccountGetTaxUSPayerNameSource (account), ==, nullptr);
 
     xaccAccountSetTaxUSPayerNameSource (account, "  ");
     g_assert_cmpstr (xaccAccountGetTaxUSPayerNameSource (account), ==, "  ");
@@ -1192,7 +1193,7 @@ test_gnc_account_kvp_setters_getters (Fixture *fixture, gconstpointer pData)
     g_assert_cmpstr (xaccAccountGetFilter (account), ==, "unset");
 
     xaccAccountSetFilter (account, "   unset ");
-    g_assert_cmpstr (xaccAccountGetFilter (account), ==, "unset");
+    g_assert_cmpstr (xaccAccountGetFilter (account), ==, "   unset ");
 
     xaccAccountSetFilter (account, "");
     g_assert_cmpstr (xaccAccountGetFilter (account), ==, nullptr);
@@ -1210,7 +1211,7 @@ test_gnc_account_kvp_setters_getters (Fixture *fixture, gconstpointer pData)
     g_assert_cmpstr (xaccAccountGetSortOrder (account), ==, "unset");
 
     xaccAccountSetSortOrder (account, "  unset ");
-    g_assert_cmpstr (xaccAccountGetSortOrder (account), ==, "unset");
+    g_assert_cmpstr (xaccAccountGetSortOrder (account), ==, "  unset ");
 
     xaccAccountSetSortOrder (account, "");
     g_assert_cmpstr (xaccAccountGetSortOrder (account), ==, nullptr);
@@ -1228,7 +1229,7 @@ test_gnc_account_kvp_setters_getters (Fixture *fixture, gconstpointer pData)
     g_assert_cmpstr (xaccAccountGetNotes (account), ==, "unset");
 
     xaccAccountSetNotes (account, "    unset ");
-    g_assert_cmpstr (xaccAccountGetNotes (account), ==, "unset");
+    g_assert_cmpstr (xaccAccountGetNotes (account), ==, "    unset ");
 
     xaccAccountSetNotes (account, "");
     g_assert_cmpstr (xaccAccountGetNotes (account), ==, nullptr);
@@ -1301,7 +1302,7 @@ test_gnc_account_kvp_setters_getters (Fixture *fixture, gconstpointer pData)
     g_assert_cmpstr (dxaccAccountGetPriceSrc (account), ==, "boo");
 
     dxaccAccountSetPriceSrc (account, "");
-    g_assert_cmpstr (dxaccAccountGetPriceSrc (account), ==, "");
+    g_assert_cmpstr (dxaccAccountGetPriceSrc (account), ==, nullptr);
 
     dxaccAccountSetPriceSrc (account, nullptr);
     g_assert_cmpstr (dxaccAccountGetPriceSrc (account), ==, nullptr);
@@ -1313,7 +1314,7 @@ test_gnc_account_kvp_setters_getters (Fixture *fixture, gconstpointer pData)
     g_assert_cmpstr (dxaccAccountGetQuoteTZ (account), ==, "boo");
 
     dxaccAccountSetQuoteTZ (account, "");
-    g_assert_cmpstr (dxaccAccountGetQuoteTZ (account), ==, "");
+    g_assert_cmpstr (dxaccAccountGetQuoteTZ (account), ==, nullptr);
 
     dxaccAccountSetQuoteTZ (account, nullptr);
     g_assert_cmpstr (dxaccAccountGetQuoteTZ (account), ==, nullptr);

commit af02dae28684f1e31c6937dc5a30df4d0e7adb01
Merge: 1eecb9f5c 76014f18a
Author: John Ralls <jralls at ceridwen.us>
Date:   Thu Mar 2 16:28:17 2023 -0800

    Fixups for merging into master instead of maint.

diff --cc libgnucash/engine/Account.cpp
index 50333b232,a3bdca000..7846db148
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@@ -4929,259 -4864,17 +4843,263 @@@ xaccAccountGetLastNum (const Account *a
  void
  xaccAccountSetLastNum (Account *acc, const char *num)
  {
-     auto priv = GET_PRIVATE (acc);
-     if (priv->last_num != is_unset)
-         g_free (priv->last_num);
-     priv->last_num = g_strdup (num);
-     set_kvp_string_tag (acc, "last-num", priv->last_num);
+     GValue v = G_VALUE_INIT;
+     g_return_if_fail(GNC_IS_ACCOUNT(acc));
+     g_value_init (&v, G_TYPE_STRING);
+ 
+     g_value_set_static_string (&v, num);
+     xaccAccountBeginEdit (acc);
+     qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {"last-num"});
+     mark_account (acc);
+     xaccAccountCommitEdit (acc);
  }
  
 +
 +/********************************************************************\
 +\********************************************************************/
 +
 +gboolean
 +xaccAccountGetHigherBalanceLimit (const Account *acc,
 +                                  gnc_numeric *balance)
 +{
 +    g_return_val_if_fail (GNC_IS_ACCOUNT(acc), false);
 +
 +    if (GET_PRIVATE(acc)->higher_balance_cached)
 +    {
 +        *balance = GET_PRIVATE(acc)->higher_balance_limit;
 +
 +        if (gnc_numeric_check (*balance) == 0)
 +            return true;
 +        else
 +            return false;
 +    }
 +    else
 +    {
 +        gnc_numeric bal = gnc_numeric_create (1,0);
 +        GValue v = G_VALUE_INIT;
 +        gboolean retval = false;
 +
 +        qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {KEY_BALANCE_LIMIT,
 +                                                           KEY_BALANCE_HIGHER_LIMIT_VALUE});
 +        if (G_VALUE_HOLDS_BOXED(&v))
 +        {
 +            bal = *(gnc_numeric*)g_value_get_boxed (&v);
 +            if (bal.denom)
 +            {
 +                if (balance)
 +                   *balance = bal;
 +                retval = true;
 +            }
 +        }
 +        g_value_unset (&v);
 +
 +        GET_PRIVATE(acc)->higher_balance_limit = bal;
 +        GET_PRIVATE(acc)->higher_balance_cached = true;
 +        return retval;
 +    }
 +}
 +
 +gboolean
 +xaccAccountGetLowerBalanceLimit (const Account *acc,
 +                                 gnc_numeric *balance)
 +{
 +    g_return_val_if_fail (GNC_IS_ACCOUNT(acc), false);
 +
 +    if (GET_PRIVATE(acc)->lower_balance_cached)
 +    {
 +        *balance = GET_PRIVATE(acc)->lower_balance_limit;
 +
 +        if (gnc_numeric_check (*balance) == 0)
 +            return true;
 +        else
 +            return false;
 +    }
 +    else
 +    {
 +        gnc_numeric bal = gnc_numeric_create (1,0);
 +        GValue v = G_VALUE_INIT;
 +        gboolean retval = false;
 +
 +        qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {KEY_BALANCE_LIMIT,
 +                                                           KEY_BALANCE_LOWER_LIMIT_VALUE});
 +        if (G_VALUE_HOLDS_BOXED(&v))
 +        {
 +            bal = *(gnc_numeric*)g_value_get_boxed (&v);
 +            if (bal.denom)
 +            {
 +                if (balance)
 +                   *balance = bal;
 +                retval = true;
 +            }
 +        }
 +        g_value_unset (&v);
 +
 +        GET_PRIVATE(acc)->lower_balance_limit = bal;
 +        GET_PRIVATE(acc)->lower_balance_cached = true;
 +        return retval;
 +    }
 +}
 +
 +
 +static void
 +set_balance_limits (Account *acc, gnc_numeric balance, gboolean higher)
 +{
 +    gnc_numeric balance_limit;
 +    gboolean balance_limit_valid;
 +    std::vector<std::string> path {KEY_BALANCE_LIMIT};
 +
 +    if (higher)
 +    {
 +        path.push_back (KEY_BALANCE_HIGHER_LIMIT_VALUE);
 +        balance_limit_valid = xaccAccountGetHigherBalanceLimit (acc, &balance_limit);
 +    }
 +    else
 +    {
 +        path.push_back (KEY_BALANCE_LOWER_LIMIT_VALUE);
 +        balance_limit_valid = xaccAccountGetLowerBalanceLimit (acc, &balance_limit);
 +    }
 +
 +    if (!balance_limit_valid  || gnc_numeric_compare (balance, balance_limit) != 0)
 +    {
 +        GValue v = G_VALUE_INIT;
 +        g_value_init (&v, GNC_TYPE_NUMERIC);
 +        g_value_set_boxed (&v, &balance);
 +        xaccAccountBeginEdit (acc);
 +
 +        qof_instance_set_path_kvp (QOF_INSTANCE(acc), &v, path);
 +        if (higher)
 +        {
 +            GET_PRIVATE(acc)->higher_balance_limit.denom = balance.denom;
 +            GET_PRIVATE(acc)->higher_balance_limit.num = balance.num;
 +            GET_PRIVATE(acc)->higher_balance_cached = true;
 +        }
 +        else
 +        {
 +            GET_PRIVATE(acc)->lower_balance_limit.denom = balance.denom;
 +            GET_PRIVATE(acc)->lower_balance_limit.num = balance.num;
 +            GET_PRIVATE(acc)->lower_balance_cached = true;
 +        }
 +        mark_account (acc);
 +        xaccAccountCommitEdit (acc);
 +        g_value_unset (&v);
 +    }
 +}
 +
 +void
 +xaccAccountSetHigherBalanceLimit (Account *acc, gnc_numeric balance)
 +{
 +    g_return_if_fail (GNC_IS_ACCOUNT(acc));
 +
 +    if (gnc_numeric_check (balance) != 0)
 +        return;
 +
 +    set_balance_limits (acc, balance, true);
 +}
 +
 +void
 +xaccAccountSetLowerBalanceLimit (Account *acc, gnc_numeric balance)
 +{
 +    g_return_if_fail (GNC_IS_ACCOUNT(acc));
 +
 +    if (gnc_numeric_check (balance) != 0)
 +        return;
 +
 +    set_balance_limits (acc, balance, false);
 +}
 +
 +
 +static void
 +clear_balance_limits (Account *acc, gboolean higher)
 +{
 +    gnc_numeric balance_limit;
 +    gboolean balance_limit_valid;
 +    std::vector<std::string> path {KEY_BALANCE_LIMIT};
 +
 +    if (higher)
 +    {
 +        path.push_back (KEY_BALANCE_HIGHER_LIMIT_VALUE);
 +        balance_limit_valid = xaccAccountGetHigherBalanceLimit (acc, &balance_limit);
 +    }
 +    else
 +    {
 +        path.push_back (KEY_BALANCE_LOWER_LIMIT_VALUE);
 +        balance_limit_valid = xaccAccountGetLowerBalanceLimit (acc, &balance_limit);
 +    }
 +
 +    if (balance_limit_valid)
 +    {
 +        xaccAccountBeginEdit (acc);
 +        qof_instance_set_path_kvp (QOF_INSTANCE(acc), nullptr, path);
 +        qof_instance_slot_path_delete_if_empty (QOF_INSTANCE(acc), {KEY_BALANCE_LIMIT});
 +        if (higher)
 +            GET_PRIVATE(acc)->higher_balance_cached = false;
 +        else
 +            GET_PRIVATE(acc)->lower_balance_cached = false;
 +        mark_account (acc);
 +        xaccAccountCommitEdit (acc);
 +    }
 +}
 +
 +void
 +xaccAccountClearHigherBalanceLimit (Account *acc)
 +{
 +    g_return_if_fail (GNC_IS_ACCOUNT(acc));
 +
 +    clear_balance_limits (acc, true);
 +}
 +
 +void
 +xaccAccountClearLowerBalanceLimit (Account *acc)
 +{
 +    g_return_if_fail (GNC_IS_ACCOUNT(acc));
 +
 +    clear_balance_limits (acc, false);
 +}
 +
 +gboolean
 +xaccAccountGetIncludeSubAccountBalances (const Account *acc)
 +{
 +    g_return_val_if_fail (GNC_IS_ACCOUNT(acc), false);
 +
 +    if (GET_PRIVATE(acc)->include_sub_account_balances == TriState::Unset)
 +    {
 +        gboolean inc_sub = boolean_from_key (acc, {KEY_BALANCE_LIMIT,
 +                                                   KEY_BALANCE_INCLUDE_SUB_ACCTS});
 +
 +        GET_PRIVATE(acc)->include_sub_account_balances = inc_sub ? TriState::True
 +                                                                 : TriState::False;
 +    }
 +    return GET_PRIVATE(acc)->include_sub_account_balances == TriState::True;
 +}
 +
 +void
 +xaccAccountSetIncludeSubAccountBalances (Account *acc, gboolean inc_sub)
 +{
 +    g_return_if_fail (GNC_IS_ACCOUNT(acc));
 +
 +    if (inc_sub != xaccAccountGetIncludeSubAccountBalances (acc))
 +    {
 +        GValue v = G_VALUE_INIT;
 +        g_value_init (&v, G_TYPE_BOOLEAN);
 +        g_value_set_boolean (&v, inc_sub);
 +        std::vector<std::string> path {KEY_BALANCE_LIMIT,
 +                                       KEY_BALANCE_INCLUDE_SUB_ACCTS};
 +        xaccAccountBeginEdit (acc);
 +        if (inc_sub)
 +            qof_instance_set_path_kvp (QOF_INSTANCE(acc), &v, path);
 +        else
 +            qof_instance_set_path_kvp (QOF_INSTANCE(acc), nullptr, path);
 +        GET_PRIVATE(acc)->include_sub_account_balances =
 +                              inc_sub ? TriState::True : TriState::False;
 +        mark_account (acc);
 +        xaccAccountCommitEdit (acc);
 +        g_value_unset (&v);
 +    }
 +}
 +
 +/********************************************************************\
 +\********************************************************************/
 +
  static Account *
  GetOrMakeOrphanAccount (Account *root, gnc_commodity * currency)
  {
diff --cc libgnucash/engine/Split.c
index bd6541206,b36e59bbf..9efe633c9
--- a/libgnucash/engine/Split.c
+++ b/libgnucash/engine/Split.c
@@@ -1967,25 -1966,24 +1964,23 @@@ const char 
  xaccSplitGetType(const Split *s)
  {
      if (!s) return NULL;
-     if (s->split_type == is_unset)
+ 
+     GValue v = G_VALUE_INIT;
 -    Split *split = (Split*) s;
+     const char* type;
+     qof_instance_get_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
+     type = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
+     const char *rv;
+     if (!type || !g_strcmp0 (type, split_type_normal))
+         rv = split_type_normal;
+     else if (!g_strcmp0 (type, split_type_stock_split))
+         rv = split_type_stock_split;
+     else
      {
-         GValue v = G_VALUE_INIT;
-         Split *split = (Split*) s;
-         const char* type;
-         qof_instance_get_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
-         type = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
-         if (!type || !g_strcmp0 (type, split_type_normal))
-             split->split_type = (char*) split_type_normal;
-         else if (!g_strcmp0 (type, split_type_stock_split))
-             split->split_type = (char*) split_type_stock_split;
-         else
-         {
-             PERR ("unexpected split-type %s, reset to normal.", type);
-             split->split_type = split_type_normal;
-         }
-         g_value_unset (&v);
+         PERR ("unexpected split-type %s, reset to normal.", type);
+         rv = split_type_normal;
      }
-     return s->split_type;
+     g_value_unset (&v);
+     return rv;
  }
  
  /* reconfigure a split to be a stock split - after this, you shouldn't
diff --cc libgnucash/engine/gnc-commodity.c
index d40000ea3,1d2627ce3..79d988a21
--- a/libgnucash/engine/gnc-commodity.c
+++ b/libgnucash/engine/gnc-commodity.c
@@@ -1491,10 -1479,10 +1479,8 @@@ voi
  gnc_commodity_set_user_symbol(gnc_commodity * cm, const char * user_symbol)
  {
      struct lconv *lc;
--    gnc_commodityPrivate* priv;
  
      if (!cm) return;
--    priv = GET_PRIVATE(cm);
  
      ENTER ("(cm=%p, symbol=%s)", cm, user_symbol ? user_symbol : "(null)");
  
diff --cc libgnucash/engine/gncInvoice.c
index bf1dcde22,4a27c5080..f4ad3cb66
--- a/libgnucash/engine/gncInvoice.c
+++ b/libgnucash/engine/gncInvoice.c
@@@ -898,15 -876,14 +876,13 @@@ const char * gncInvoiceGetNotes (const 
  const char * gncInvoiceGetDocLink (const GncInvoice *invoice)
  {
      if (!invoice) return NULL;
-     if (invoice->doclink == is_unset)
-     {
-         GValue v = G_VALUE_INIT;
-         GncInvoice *inv = (GncInvoice*) invoice;
-         qof_instance_get_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_DOCLINK);
-         inv->doclink = G_VALUE_HOLDS_STRING(&v) ? g_value_dup_string (&v) : NULL;
-         g_value_unset (&v);
-     }
-     return invoice->doclink;
+ 
+     GValue v = G_VALUE_INIT;
 -    GncInvoice *inv = (GncInvoice*) invoice;
+     qof_instance_get_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_DOCLINK);
+     const char *rv = G_VALUE_HOLDS_STRING(&v) ? g_value_get_string (&v) : NULL;
+     g_value_unset (&v);
+ 
+     return rv;
  }
  
  GncOwnerType gncInvoiceGetOwnerType (const GncInvoice *invoice)
diff --cc po/hu.po
index 09fbf9e51,b8b40f325..fcdacdcd1
--- a/po/hu.po
+++ b/po/hu.po
@@@ -14,10 -14,10 +14,10 @@@ msgstr "
  "Report-Msgid-Bugs-To: https://bugs.gnucash.org/enter_bug."
  "cgi?product=GnuCash&component=Translations\n"
  "POT-Creation-Date: 2022-12-04 19:47-0800\n"
- "PO-Revision-Date: 2023-02-26 20:44+0000\n"
+ "PO-Revision-Date: 2023-02-27 18:39+0000\n"
  "Last-Translator: mocsa <csaba at feltoltve.hu>\n"
  "Language-Team: Hungarian <https://hosted.weblate.org/projects/gnucash/"
 -"gnucash/hu/>\n"
 +"program-beta/hu/>\n"
  "Language: hu\n"
  "MIME-Version: 1.0\n"
  "Content-Type: text/plain; charset=UTF-8\n"

commit 76014f18a0178cfe8da36b85b24363becad134fb
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed Mar 1 23:53:25 2023 +0800

    [account.cpp] don't cache char* [fails]

diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 0e659e8d9..a3bdca000 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -289,8 +289,6 @@ mark_account (Account *acc)
 /********************************************************************\
 \********************************************************************/
 
-static constexpr const char* is_unset {"unset"};
-
 /* GObject Initialization */
 G_DEFINE_TYPE_WITH_PRIVATE(Account, gnc_account, QOF_TYPE_INSTANCE)
 
@@ -328,16 +326,6 @@ gnc_account_init(Account* acc)
     priv->starting_reconciled_balance = gnc_numeric_zero();
     priv->balance_dirty = FALSE;
 
-    priv->last_num = (char*) is_unset;
-    priv->tax_us_code = (char*) is_unset;
-    priv->tax_us_pns = (char*) is_unset;
-    priv->color = (char*) is_unset;
-    priv->sort_order = (char*) is_unset;
-    priv->notes = (char*) is_unset;
-    priv->filter = (char*) is_unset;
-    priv->equity_type = TriState::Unset;
-    priv->sort_reversed = TriState::Unset;
-
     priv->splits = NULL;
     priv->sort_dirty = FALSE;
 }
@@ -1396,21 +1384,6 @@ xaccFreeAccount (Account *acc)
     qof_string_cache_remove(priv->description);
     priv->accountName = priv->accountCode = priv->description = nullptr;
 
-    if (priv->last_num != is_unset)
-        g_free (priv->last_num);
-    if (priv->tax_us_code != is_unset)
-        g_free (priv->tax_us_code);
-    if (priv->tax_us_pns != is_unset)
-        g_free (priv->tax_us_pns);
-    if (priv->color != is_unset)
-        g_free (priv->color);
-    if (priv->sort_order != is_unset)
-        g_free (priv->sort_order);
-    if (priv->notes != is_unset)
-        g_free (priv->notes);
-    if (priv->filter != is_unset)
-        g_free (priv->filter);
-
     /* zero out values, just in case stray
      * pointers are pointing here. */
 
@@ -2501,21 +2474,6 @@ xaccAccountSetDescription (Account *acc, const char *str)
     xaccAccountCommitEdit(acc);
 }
 
-static char*
-stripdup_or_null (const char *value)
-{
-    if (value)
-    {
-        auto temp = g_strstrip (g_strdup (value));
-        if (*temp)
-            return temp;
-        g_free (temp);
-    }
-    return nullptr;
-}
-
-// note the *value argument is expected to be either a strstripped
-// char* or nullptr, as returned by stripdup_or_null above.
 static void
 set_kvp_string_path (Account *acc, std::vector<std::string> const & path,
                      const char *value)
@@ -2527,7 +2485,7 @@ set_kvp_string_path (Account *acc, std::vector<std::string> const & path,
     {
         GValue v = G_VALUE_INIT;
         g_value_init (&v, G_TYPE_STRING);
-        g_value_set_string (&v, value);
+        g_value_set_static_string (&v, value);
         qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, path);
         g_value_unset (&v);
     }
@@ -2545,58 +2503,43 @@ set_kvp_string_tag (Account *acc, const char *tag, const char *value)
     set_kvp_string_path (acc, {tag}, value);
 }
 
-static char*
-get_kvp_string_path (const Account *acc, std::vector<std::string> const & path)
+static const char*
+get_kvp_string_path (const Account *acc, std::vector<std::string> const & path,
+                     GValue *v)
 {
-    GValue v = G_VALUE_INIT;
+    *v = G_VALUE_INIT;
     if (acc == NULL) return NULL; // how to check path is valid??
-    qof_instance_get_path_kvp (QOF_INSTANCE (acc), &v, path);
-    auto retval = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
-    g_value_unset (&v);
-    return retval;
+    qof_instance_get_path_kvp (QOF_INSTANCE (acc), v, path);
+    return G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (v) : NULL;
 }
 
-static char*
-get_kvp_string_tag (const Account *acc, const char *tag)
+static const char*
+get_kvp_string_tag (const Account *acc, const char *tag, GValue *v)
 {
-    return get_kvp_string_path (acc, {tag});
+    return get_kvp_string_path (acc, {tag}, v);
 }
 
 void
 xaccAccountSetColor (Account *acc, const char *str)
 {
-    auto priv = GET_PRIVATE (acc);
-    if (priv->color != is_unset)
-        g_free (priv->color);
-    priv->color = stripdup_or_null (str);
-    set_kvp_string_tag (acc, "color", priv->color);
+    set_kvp_string_tag (acc, "color", str);
 }
 
 void
 xaccAccountSetFilter (Account *acc, const char *str)
 {
-    auto priv = GET_PRIVATE (acc);
-    if (priv->filter != is_unset)
-        g_free (priv->filter);
-    priv->filter = stripdup_or_null (str);
-    set_kvp_string_tag (acc, "filter", priv->filter);
+    set_kvp_string_tag (acc, "filter", str);
 }
 
 void
 xaccAccountSetSortOrder (Account *acc, const char *str)
 {
-    auto priv = GET_PRIVATE (acc);
-    if (priv->sort_order != is_unset)
-        g_free (priv->sort_order);
-    priv->sort_order = stripdup_or_null (str);
-    set_kvp_string_tag (acc, "sort-order", priv->sort_order);
+    set_kvp_string_tag (acc, "sort-order", str);
 }
 
 void
 xaccAccountSetSortReversed (Account *acc, gboolean sortreversed)
 {
-    auto priv = GET_PRIVATE (acc);
-    priv->sort_reversed = sortreversed ? TriState::True : TriState::False;
     set_kvp_string_tag (acc, "sort-reversed", sortreversed ? "true" : NULL);
 }
 
@@ -2621,11 +2564,7 @@ qofAccountSetParent (Account *acc, QofInstance *parent)
 void
 xaccAccountSetNotes (Account *acc, const char *str)
 {
-    auto priv = GET_PRIVATE (acc);
-    if (priv->notes != is_unset)
-        g_free (priv->notes);
-    priv->notes = stripdup_or_null (str);
-    set_kvp_string_tag (acc, "notes", priv->notes);
+    set_kvp_string_tag (acc, "notes", str);
 }
 
 void
@@ -2748,7 +2687,7 @@ DxaccAccountSetCurrency (Account * acc, gnc_commodity * currency)
 
     if ((!acc) || (!currency)) return;
     g_value_init (&v, G_TYPE_STRING);
-    g_value_set_string (&v, s);
+    g_value_set_static_string (&v, s);
     qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {"old-currency"});
     mark_account (acc);
     xaccAccountCommitEdit(acc);
@@ -3369,57 +3308,51 @@ xaccAccountGetDescription (const Account *acc)
 const char *
 xaccAccountGetColor (const Account *acc)
 {
+    GValue v = G_VALUE_INIT;
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
-    auto priv = GET_PRIVATE (acc);
-    if (priv->color == is_unset)
-        priv->color = get_kvp_string_tag (acc, "color");
-    return priv->color;
+    auto rv = get_kvp_string_tag (acc, "color", &v);
+    g_value_unset (&v);
+    return rv;
 }
 
 const char *
 xaccAccountGetFilter (const Account *acc)
 {
+    GValue v = G_VALUE_INIT;
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
-    auto priv = GET_PRIVATE (acc);
-    if (priv->filter == is_unset)
-        priv->filter = get_kvp_string_tag (acc, "filter");
-    return priv->filter;
+    auto rv = get_kvp_string_tag (acc, "filter", &v);
+    g_value_unset (&v);
+    return rv;
 }
 
 const char *
 xaccAccountGetSortOrder (const Account *acc)
 {
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), 0);
-    auto priv = GET_PRIVATE (acc);
-    if (priv->sort_order == is_unset)
-        priv->sort_order = get_kvp_string_tag (acc, "sort-order");
-    return priv->sort_order;
+    GValue v = G_VALUE_INIT;
+    auto rv = get_kvp_string_tag (acc, "sort-order", &v);
+    g_value_unset (&v);
+    return rv;
 }
 
 gboolean
 xaccAccountGetSortReversed (const Account *acc)
 {
-
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
-    auto priv = GET_PRIVATE (acc);
-    if (priv->sort_reversed == TriState::Unset)
-    {
-        auto sort_reversed = get_kvp_string_tag (acc, "sort-reversed");
-        priv->sort_reversed = g_strcmp0 (sort_reversed, "true") ?
-            TriState::False : TriState::True;
-        g_free (sort_reversed);
-    }
-    return (priv->sort_reversed == TriState::True);
+    GValue v = G_VALUE_INIT;
+    auto rv = !g_strcmp0 (get_kvp_string_tag (acc, "sort-reversed", &v), "true");
+    g_value_unset (&v);
+    return rv;
 }
 
 const char *
 xaccAccountGetNotes (const Account *acc)
 {
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL);
-    auto priv = GET_PRIVATE (acc);
-    if (priv->notes == is_unset)
-        priv->notes = get_kvp_string_tag (acc, "notes");
-    return priv->notes;
+    GValue v = G_VALUE_INIT;
+    auto rv = get_kvp_string_tag (acc, "notes", &v);
+    g_value_unset (&v);
+    return rv;
 }
 
 gnc_commodity *
@@ -4157,39 +4090,31 @@ xaccAccountSetTaxRelated (Account *acc, gboolean tax_related)
 const char *
 xaccAccountGetTaxUSCode (const Account *acc)
 {
-    auto priv = GET_PRIVATE (acc);
-    if (priv->tax_us_code == is_unset)
-        priv->tax_us_code = get_kvp_string_path (acc, {"tax-US", "code"});
-    return priv->tax_us_code;
+    GValue v = G_VALUE_INIT;
+    g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {"tax-US", "code"});
+    return G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
 }
 
 void
 xaccAccountSetTaxUSCode (Account *acc, const char *code)
 {
-    auto priv = GET_PRIVATE (acc);
-    if (priv->tax_us_code != is_unset)
-        g_free (priv->tax_us_code);
-    priv->tax_us_code = g_strdup (code);
-    set_kvp_string_path (acc, {"tax-US", "code"}, priv->tax_us_code);
+    set_kvp_string_path (acc, {"tax-US", "code"}, code);
 }
 
 const char *
 xaccAccountGetTaxUSPayerNameSource (const Account *acc)
 {
-    auto priv = GET_PRIVATE (acc);
-    if (priv->tax_us_pns == is_unset)
-        priv->tax_us_pns = get_kvp_string_path (acc, {"tax-US", "payer-name-source"});
-    return priv->tax_us_pns;
- }
+    GValue v = G_VALUE_INIT;
+    g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {"tax-US", "payer-name-source"});
+    return G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
+}
 
 void
 xaccAccountSetTaxUSPayerNameSource (Account *acc, const char *source)
 {
-    auto priv = GET_PRIVATE (acc);
-    if (priv->tax_us_pns != is_unset)
-        g_free (priv->tax_us_pns);
-    priv->tax_us_pns = g_strdup (source);
-    set_kvp_string_path (acc, {"tax-US", "payer-name-source"}, priv->tax_us_pns);
+    set_kvp_string_path (acc, {"tax-US", "payer-name-source"}, source);
 }
 
 gint64
@@ -4287,15 +4212,12 @@ xaccAccountGetIsOpeningBalance (const Account *acc)
 {
     if (GET_PRIVATE(acc)->type != ACCT_TYPE_EQUITY)
         return false;
-    auto priv = GET_PRIVATE(acc);
-    if (priv->equity_type == TriState::Unset)
-    {
-        auto equity_type = get_kvp_string_tag (acc, "equity-type");
-        priv->equity_type = g_strcmp0 (equity_type, "opening-balance") ?
-            TriState::False : TriState::True;
-        g_free (equity_type);
-    }
-    return (priv->equity_type == TriState::True);
+
+    GValue v = G_VALUE_INIT;
+    auto rv = !g_strcmp0 (get_kvp_string_tag (acc, "equity-type", &v),
+                          "opening-balance");
+    g_value_unset (&v);
+    return rv;
 }
 
 void
@@ -4303,8 +4225,6 @@ xaccAccountSetIsOpeningBalance (Account *acc, gboolean val)
 {
     if (GET_PRIVATE(acc)->type != ACCT_TYPE_EQUITY)
         return;
-    auto priv = GET_PRIVATE (acc);
-    priv->equity_type = val ? TriState::True : TriState::False;
     set_kvp_string_tag(acc, "equity-type", val ? "opening-balance" : nullptr);
 }
 
@@ -4932,10 +4852,10 @@ xaccAccountClearReconcilePostpone (Account *acc)
 const char *
 xaccAccountGetLastNum (const Account *acc)
 {
-    auto priv = GET_PRIVATE (acc);
-    if (priv->last_num == is_unset)
-        priv->last_num = get_kvp_string_tag (acc, "last-num");
-    return priv->last_num;
+    GValue v = G_VALUE_INIT;
+    g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {"last-num"});
+    return G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
 }
 
 /********************************************************************\
@@ -4944,11 +4864,15 @@ xaccAccountGetLastNum (const Account *acc)
 void
 xaccAccountSetLastNum (Account *acc, const char *num)
 {
-    auto priv = GET_PRIVATE (acc);
-    if (priv->last_num != is_unset)
-        g_free (priv->last_num);
-    priv->last_num = g_strdup (num);
-    set_kvp_string_tag (acc, "last-num", priv->last_num);
+    GValue v = G_VALUE_INIT;
+    g_return_if_fail(GNC_IS_ACCOUNT(acc));
+    g_value_init (&v, G_TYPE_STRING);
+
+    g_value_set_static_string (&v, num);
+    xaccAccountBeginEdit (acc);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {"last-num"});
+    mark_account (acc);
+    xaccAccountCommitEdit (acc);
 }
 
 static Account *
@@ -5057,8 +4981,11 @@ dxaccAccountGetPriceSrc(const Account *acc)
     if (!xaccAccountIsPriced(acc)) return NULL;
 
     g_free (source);
-    source = get_kvp_string_tag (acc, "old-price-source");
-    return source;
+
+    GValue v = G_VALUE_INIT;
+    auto rv = get_kvp_string_tag (acc, "old-price-source", &v);
+    g_value_unset (&v);
+    return rv;
 }
 
 /********************************************************************\
@@ -5078,12 +5005,12 @@ dxaccAccountSetQuoteTZ(Account *acc, const char *tz)
 const char*
 dxaccAccountGetQuoteTZ(const Account *acc)
 {
-    static char *quote_tz = nullptr;
     if (!acc) return NULL;
     if (!xaccAccountIsPriced(acc)) return NULL;
-    g_free (quote_tz);
-    quote_tz = get_kvp_string_tag (acc, "old-quote-tz");
-    return quote_tz;
+    GValue v = G_VALUE_INIT;
+    auto rv = get_kvp_string_tag (acc, "old-quote-tz", &v);
+    g_value_unset (&v);
+    return rv;
 }
 
 /********************************************************************\
@@ -6060,10 +5987,12 @@ gnc_account_imap_get_info (Account *acc, const char *category)
 gchar *
 gnc_account_get_map_entry (Account *acc, const char *head, const char *category)
 {
-    if (category)
-        return get_kvp_string_path (acc, {head, category});
-    else
-        return get_kvp_string_path (acc, {head});
+    GValue v = G_VALUE_INIT;
+    auto rv = g_strdup (category ?
+                        get_kvp_string_path (acc, {head, category}, &v) :
+                        get_kvp_string_path (acc, {head}, &v));
+    g_value_unset (&v);
+    return rv;
 }
 
 
diff --git a/libgnucash/engine/qofinstance.cpp b/libgnucash/engine/qofinstance.cpp
index 97c3063e4..3a9c03d9d 100644
--- a/libgnucash/engine/qofinstance.cpp
+++ b/libgnucash/engine/qofinstance.cpp
@@ -1070,15 +1070,7 @@ qof_instance_set_kvp (QofInstance * inst, GValue const * value, unsigned count,
 
 void qof_instance_get_path_kvp (QofInstance * inst, GValue * value, std::vector<std::string> const & path)
 {
-    auto temp = gvalue_from_kvp_value (inst->kvp_data->get_slot (path));
-    if (G_IS_VALUE (temp))
-    {
-        if (G_IS_VALUE (value))
-            g_value_unset (value);
-        g_value_init (value, G_VALUE_TYPE (temp));
-        g_value_copy (temp, value);
-        gnc_gvalue_free (temp);
-    }
+    gvalue_from_kvp_value (inst->kvp_data->get_slot (path), value);
 }
 
 void

commit 3d381eb6fd9695a31f94f4480a7a3266220b21ea
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed Mar 1 19:49:33 2023 +0800

    [gnc-lot] don't cache char*

diff --git a/libgnucash/engine/gnc-lot.c b/libgnucash/engine/gnc-lot.c
index dd0cec9dd..2c7c7f882 100644
--- a/libgnucash/engine/gnc-lot.c
+++ b/libgnucash/engine/gnc-lot.c
@@ -106,9 +106,6 @@ typedef struct GNCLotPrivate
 
 /* ============================================================= */
 
-static char*
-is_unset = "unset";
-
 /* GObject Initialization */
 G_DEFINE_TYPE_WITH_PRIVATE(GNCLot, gnc_lot, QOF_TYPE_INSTANCE)
 
@@ -122,8 +119,6 @@ gnc_lot_init(GNCLot* lot)
     priv->splits = NULL;
     priv->cached_invoice = NULL;
     priv->is_closed = LOT_CLOSED_UNKNOWN;
-    priv->title = is_unset;
-    priv->notes = is_unset;
     priv->marker = 0;
 }
 
@@ -303,14 +298,6 @@ gnc_lot_free(GNCLot* lot)
     if (priv->account && !qof_instance_get_destroying(priv->account))
         xaccAccountRemoveLot (priv->account, lot);
 
-    if (priv->notes != is_unset)
-        g_free (priv->notes);
-
-    if (priv->title != is_unset)
-        g_free (priv->title);
-
-    priv->notes = NULL;
-    priv->title = NULL;
     priv->account = NULL;
     priv->is_closed = TRUE;
     /* qof_instance_release (&lot->inst); */
@@ -459,50 +446,37 @@ gint gnc_lot_count_splits (const GNCLot *lot)
 const char *
 gnc_lot_get_title (const GNCLot *lot)
 {
-    GNCLotPrivate* priv;
     if (!lot) return NULL;
-    priv = GET_PRIVATE (lot);
-    if (priv->title == is_unset)
-    {
-        GNCLotPrivate* priv = GET_PRIVATE (lot);
-        GValue v = G_VALUE_INIT;
-        qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "title");
-        priv->title = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
-        g_value_unset (&v);
-    }
-    return priv->title;
+
+    GValue v = G_VALUE_INIT;
+    qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "title");
+    const char *rv = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
+    g_value_unset (&v);
+
+    return rv;
 }
 
 const char *
 gnc_lot_get_notes (const GNCLot *lot)
 {
-    GNCLotPrivate* priv;
     if (!lot) return NULL;
-    priv = GET_PRIVATE (lot);
-    if (priv->notes == is_unset)
-    {
-        GValue v = G_VALUE_INIT;
-        qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
-        priv->notes = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
-        g_value_unset (&v);
-    }
-    return priv->notes;
+
+    GValue v = G_VALUE_INIT;
+    qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
+    const char *rv = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
+    g_value_unset (&v);
+    return rv;
 }
 
 void
 gnc_lot_set_title (GNCLot *lot, const char *str)
 {
     GValue v = G_VALUE_INIT;
-    GNCLotPrivate* priv;
     if (!lot) return;
-    priv = GET_PRIVATE (lot);
-    if (priv->title != is_unset)
-        g_free (priv->title);
 
     qof_begin_edit(QOF_INSTANCE(lot));
     g_value_init (&v, G_TYPE_STRING);
-    g_value_set_string (&v, str);
-    priv->title = g_strdup (str);
+    g_value_set_static_string (&v, str);
     qof_instance_set_kvp (QOF_INSTANCE (lot), &v, 1, "title");
     qof_instance_set_dirty(QOF_INSTANCE(lot));
     gnc_lot_commit_edit(lot);
@@ -513,15 +487,11 @@ void
 gnc_lot_set_notes (GNCLot *lot, const char *str)
 {
     GValue v = G_VALUE_INIT;
-    GNCLotPrivate* priv;
     if (!lot) return;
-    priv = GET_PRIVATE (lot);
-    if (priv->notes != is_unset)
-        g_free (priv->notes);
+
     qof_begin_edit(QOF_INSTANCE(lot));
     g_value_init (&v, G_TYPE_STRING);
-    g_value_set_string (&v, str);
-    priv->notes = g_strdup (str);
+    g_value_set_static_string (&v, str);
     qof_instance_set_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
     qof_instance_set_dirty(QOF_INSTANCE(lot));
     gnc_lot_commit_edit(lot);

commit 50f998fad84e5602b98376c02569016ee0167b41
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed Mar 1 19:49:27 2023 +0800

    [gncInvoice] don't cache char*

diff --git a/libgnucash/engine/gncInvoice.c b/libgnucash/engine/gncInvoice.c
index eedad7c70..4a27c5080 100644
--- a/libgnucash/engine/gncInvoice.c
+++ b/libgnucash/engine/gncInvoice.c
@@ -66,8 +66,6 @@ struct _gncInvoice
     time64        date_opened;
     time64        date_posted;
 
-    char          *doclink;
-
     gnc_numeric   to_charge_amount;
 
     gnc_commodity *currency;
@@ -285,9 +283,6 @@ impl_get_typed_referring_object_list (const QofInstance* inst, const QofInstance
     return qof_instance_get_referring_object_list_from_collection (qof_instance_get_collection (inst), ref);
 }
 
-static const char*
-is_unset = "unset";
-
 static void
 gnc_invoice_class_init (GncInvoiceClass *klass)
 {
@@ -333,7 +328,6 @@ GncInvoice *gncInvoiceCreate (QofBook *book)
     invoice->active = TRUE;
 
     invoice->to_charge_amount = gnc_numeric_zero ();
-    invoice->doclink = (char*) is_unset;
 
     qof_event_gen (&invoice->inst, QOF_EVENT_CREATE, NULL);
 
@@ -379,10 +373,7 @@ GncInvoice *gncInvoiceCopy (const GncInvoice *from)
     // Oops. Do not forget to copy the pointer to the correct currency here.
     invoice->currency = from->currency;
 
-    if (from->doclink == is_unset)
-        invoice->doclink = (char*)is_unset;
-    else
-        gncInvoiceSetDocLink (invoice, from->doclink);
+    gncInvoiceSetDocLink (invoice, gncInvoiceGetDocLink (from));
 
     // Copy all invoice->entries
     for (node = from->entries; node; node = node->next)
@@ -444,9 +435,6 @@ static void gncInvoiceFree (GncInvoice *invoice)
             gncBillTermDecRef (invoice->terms);
     }
 
-    if (invoice->doclink != is_unset)
-        g_free (invoice->doclink);
-
     /* qof_instance_release (&invoice->inst); */
     g_object_unref (invoice);
 }
@@ -558,28 +546,18 @@ void gncInvoiceSetDocLink (GncInvoice *invoice, const char *doclink)
 {
     if (!invoice || !doclink) return;
 
-    if (invoice->doclink != is_unset)
-    {
-        if (!g_strcmp0 (doclink, invoice->doclink))
-            return;
-
-        g_free (invoice->doclink);
-    }
-
     gncInvoiceBeginEdit (invoice);
 
     if (doclink[0] == '\0')
     {
-        invoice->doclink = NULL;
         qof_instance_set_kvp (QOF_INSTANCE (invoice), NULL, 1, GNC_INVOICE_DOCLINK);
     }
     else
     {
         GValue v = G_VALUE_INIT;
         g_value_init (&v, G_TYPE_STRING);
-        g_value_set_string (&v, doclink);
+        g_value_set_static_string (&v, doclink);
         qof_instance_set_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_DOCLINK);
-        invoice->doclink = g_strdup (doclink);
         g_value_unset (&v);
     }
     qof_instance_set_dirty (QOF_INSTANCE(invoice));
@@ -898,15 +876,14 @@ const char * gncInvoiceGetNotes (const GncInvoice *invoice)
 const char * gncInvoiceGetDocLink (const GncInvoice *invoice)
 {
     if (!invoice) return NULL;
-    if (invoice->doclink == is_unset)
-    {
-        GValue v = G_VALUE_INIT;
-        GncInvoice *inv = (GncInvoice*) invoice;
-        qof_instance_get_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_DOCLINK);
-        inv->doclink = G_VALUE_HOLDS_STRING(&v) ? g_value_dup_string (&v) : NULL;
-        g_value_unset (&v);
-    }
-    return invoice->doclink;
+
+    GValue v = G_VALUE_INIT;
+    GncInvoice *inv = (GncInvoice*) invoice;
+    qof_instance_get_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_DOCLINK);
+    const char *rv = G_VALUE_HOLDS_STRING(&v) ? g_value_get_string (&v) : NULL;
+    g_value_unset (&v);
+
+    return rv;
 }
 
 GncOwnerType gncInvoiceGetOwnerType (const GncInvoice *invoice)

commit c9dc71978b12ba6cbaf1a5cceaa01c0c9f13356a
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed Mar 1 19:49:20 2023 +0800

    [gnc-commodity] don't cache char*

diff --git a/libgnucash/engine/gnc-commodity.c b/libgnucash/engine/gnc-commodity.c
index 4d5ecea61..1d2627ce3 100644
--- a/libgnucash/engine/gnc-commodity.c
+++ b/libgnucash/engine/gnc-commodity.c
@@ -92,9 +92,6 @@ typedef struct gnc_commodityPrivate
     const char *default_symbol;
 } gnc_commodityPrivate;
 
-static const char*
-is_unset = "unset";
-
 #define GET_PRIVATE(o) \
     ((gnc_commodityPrivate*)gnc_commodity_get_instance_private((gnc_commodity*)o))
 
@@ -673,7 +670,6 @@ gnc_commodity_init(gnc_commodity* com)
     priv->quote_flag = 0;
     priv->quote_source = NULL;
     priv->quote_tz = CACHE_INSERT("");
-    priv->user_symbol = (char*) is_unset;
 
     reset_printname(priv);
     reset_unique_name(priv);
@@ -958,10 +954,6 @@ commodity_free(gnc_commodity * cm)
     g_free(priv->unique_name);
     priv->unique_name = NULL;
 
-    if (priv->user_symbol != is_unset)
-        g_free (priv->user_symbol);
-    priv->user_symbol = NULL;
-
 #ifdef ACCOUNTS_CLEANED_UP
     /* Account objects are not actually cleaned up when a book is closed (in fact
      * a memory leak), but commodities are, so in currently this warning gets hit
@@ -1193,17 +1185,13 @@ gnc_commodity_get_quote_tz(const gnc_commodity *cm)
 const char*
 gnc_commodity_get_user_symbol(const gnc_commodity *cm)
 {
-    gnc_commodityPrivate* priv;
     g_return_val_if_fail (GNC_IS_COMMODITY (cm), NULL);
-    priv = GET_PRIVATE(cm);
-    if (priv->user_symbol == is_unset)
-    {
-        GValue v = G_VALUE_INIT;
-        qof_instance_get_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
-        priv->user_symbol = G_VALUE_HOLDS_STRING (&v) ? g_value_dup_string (&v) : NULL;
-        g_value_unset (&v);
-    }
-    return priv->user_symbol;
+
+    GValue v = G_VALUE_INIT;
+    qof_instance_get_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
+    const char *rv = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
+    g_value_unset (&v);
+    return rv;
 }
 
 /********************************************************************
@@ -1509,31 +1497,19 @@ gnc_commodity_set_user_symbol(gnc_commodity * cm, const char * user_symbol)
     else if (!g_strcmp0(user_symbol, gnc_commodity_get_default_symbol(cm)))
 	user_symbol = NULL;
 
-    if (priv->user_symbol != is_unset)
-    {
-        if (!g_strcmp0 (user_symbol, priv->user_symbol))
-        {
-            LEAVE ("gnc_commodity_set_user_symbol: no change");
-            return;
-        }
-        g_free (priv->user_symbol);
-    }
-
     gnc_commodity_begin_edit (cm);
 
     if (user_symbol)
     {
         GValue v = G_VALUE_INIT;
         g_value_init (&v, G_TYPE_STRING);
-        g_value_set_string (&v, user_symbol);
+        g_value_set_static_string (&v, user_symbol);
         qof_instance_set_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
-        priv->user_symbol = g_strdup (user_symbol);
         g_value_unset (&v);
     }
     else
     {
         qof_instance_set_kvp (QOF_INSTANCE(cm), NULL, 1, "user_symbol");
-        priv->user_symbol = NULL;
     }
 
     mark_commodity_dirty(cm);

commit 57fcaabd8f640ef82870075618be25455b7d8aa3
Author: Christopher Lam <christopher.lck at gmail.com>
Date:   Wed Mar 1 19:49:04 2023 +0800

    [Split.c] don't cache char*

diff --git a/libgnucash/engine/Split.c b/libgnucash/engine/Split.c
index af9588982..b36e59bbf 100644
--- a/libgnucash/engine/Split.c
+++ b/libgnucash/engine/Split.c
@@ -97,7 +97,6 @@ enum
 
 };
 
-static const char * is_unset = "unset";
 static const char * split_type_normal = "normal";
 static const char * split_type_stock_split = "stock-split";
 
@@ -120,7 +119,6 @@ gnc_split_init(Split* split)
     split->value       = gnc_numeric_zero();
 
     split->date_reconciled  = 0;
-    split->split_type = is_unset;
 
     split->balance             = gnc_numeric_zero();
     split->cleared_balance     = gnc_numeric_zero();
@@ -721,7 +719,6 @@ xaccFreeSplit (Split *split)
     split->lot         = NULL;
     split->acc         = NULL;
     split->orig_acc    = NULL;
-    split->split_type  = NULL;
 
     split->date_reconciled = 0;
     G_OBJECT_CLASS (QOF_INSTANCE_GET_CLASS (&split->inst))->dispose(G_OBJECT (split));
@@ -1969,25 +1966,24 @@ const char *
 xaccSplitGetType(const Split *s)
 {
     if (!s) return NULL;
-    if (s->split_type == is_unset)
+
+    GValue v = G_VALUE_INIT;
+    Split *split = (Split*) s;
+    const char* type;
+    qof_instance_get_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
+    type = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
+    const char *rv;
+    if (!type || !g_strcmp0 (type, split_type_normal))
+        rv = split_type_normal;
+    else if (!g_strcmp0 (type, split_type_stock_split))
+        rv = split_type_stock_split;
+    else
     {
-        GValue v = G_VALUE_INIT;
-        Split *split = (Split*) s;
-        const char* type;
-        qof_instance_get_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
-        type = G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
-        if (!type || !g_strcmp0 (type, split_type_normal))
-            split->split_type = (char*) split_type_normal;
-        else if (!g_strcmp0 (type, split_type_stock_split))
-            split->split_type = (char*) split_type_stock_split;
-        else
-        {
-            PERR ("unexpected split-type %s, reset to normal.", type);
-            split->split_type = split_type_normal;
-        }
-        g_value_unset (&v);
+        PERR ("unexpected split-type %s, reset to normal.", type);
+        rv = split_type_normal;
     }
-    return s->split_type;
+    g_value_unset (&v);
+    return rv;
 }
 
 /* reconfigure a split to be a stock split - after this, you shouldn't
@@ -2001,7 +1997,6 @@ xaccSplitMakeStockSplit(Split *s)
     s->value = gnc_numeric_zero();
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_static_string (&v, split_type_stock_split);
-    s->split_type = split_type_stock_split;
     qof_instance_set_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
     SET_GAINS_VDIRTY(s);
     mark_split(s);



Summary of changes:
 libgnucash/engine/Account.cpp            | 239 +++++++++++--------------------
 libgnucash/engine/Split.c                |  36 ++---
 libgnucash/engine/gnc-commodity.c        |  40 +-----
 libgnucash/engine/gnc-lot.c              |  62 +++-----
 libgnucash/engine/gncInvoice.c           |  42 ++----
 libgnucash/engine/qofinstance.cpp        |  10 +-
 libgnucash/engine/test/utest-Account.cpp |  15 +-
 7 files changed, 137 insertions(+), 307 deletions(-)



More information about the gnucash-changes mailing list