gnucash unstable: Multiple changes pushed

Geert Janssens gjanssens at code.gnucash.org
Sat Dec 23 09:39:47 EST 2017


Updated	 via  https://github.com/Gnucash/gnucash/commit/2f96b19c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/a80318ec (commit)
	 via  https://github.com/Gnucash/gnucash/commit/a23438d5 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/805549ba (commit)
	 via  https://github.com/Gnucash/gnucash/commit/fbf4843f (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f782be1a (commit)
	 via  https://github.com/Gnucash/gnucash/commit/3312fe2d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/29ad8ff9 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/4a88f05d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/5b031829 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/f260a01b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/55154959 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/d9eebd33 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/5636afc4 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/2cda65e0 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9d7ec35c (commit)
	 via  https://github.com/Gnucash/gnucash/commit/eb6dad86 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/b3667c76 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/08aa0104 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/34e0d6cf (commit)
	 via  https://github.com/Gnucash/gnucash/commit/eb6c741b (commit)
	from  https://github.com/Gnucash/gnucash/commit/ddfd38d8 (commit)



commit 2f96b19c77675a883efce2eed6ecfd4d53551fad
Merge: ddfd38d a80318e
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sat Dec 23 15:10:48 2017 +0100

    Merge branch 'fix_bayes' of https://github.com/limitedAtonement/gnucash into unstable


commit a80318ec5f05715b843bf0a038159076342ae0db
Author: lmat <dartme18 at gmail.com>
Date:   Thu Dec 21 07:41:07 2017 -0500

    Adding to version info to feature string

diff --git a/libgnucash/engine/gnc-features.c b/libgnucash/engine/gnc-features.c
index 0c58bad..4d38fa7 100644
--- a/libgnucash/engine/gnc-features.c
+++ b/libgnucash/engine/gnc-features.c
@@ -46,7 +46,7 @@ static gncFeature known_features[] =
     { GNC_FEATURE_KVP_EXTRA_DATA, "Extra data for addresses, jobs or invoice entries (requires at least GnuCash 2.6.4)" },
     { GNC_FEATURE_BOOK_CURRENCY, "User specifies a 'book-currency'; costs of other currencies/commodities tracked in terms of book-currency (requires at least GnuCash 2.7.0)" },
     { GNC_FEATURE_GUID_BAYESIAN, "Use account GUID as key for Bayesian data (requires at least GnuCash 2.6.12)" },
-    { GNC_FEATURE_GUID_FLAT_BAYESIAN, "Use account GUID as key for bayesian data and store KVP flat" },
+    { GNC_FEATURE_GUID_FLAT_BAYESIAN, "Use account GUID as key for bayesian data and store KVP flat (requires at least Gnucash 2.6.19)" },
     { NULL },
 };
 

commit a23438d5fbbc6cdb24d26f5a921b70fecb64750b
Author: lmat <dartme18 at gmail.com>
Date:   Tue Dec 12 09:34:44 2017 -0800

    Correct string cache code
    
    string cache replace was incorrect and covered by gpointer casting.

diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index f04c43a..a4d4995 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -1108,7 +1108,7 @@ gnc_account_create_root (QofBook *book)
     rpriv = GET_PRIVATE(root);
     xaccAccountBeginEdit(root);
     rpriv->type = ACCT_TYPE_ROOT;
-    qof_string_cache_replace((void const **)(&rpriv->accountName), "Root Account");
+    rpriv->accountName = qof_string_cache_replace(rpriv->accountName, "Root Account");
     mark_account (root);
     xaccAccountCommitEdit(root);
     gnc_book_set_root_account(book, root);
@@ -2245,7 +2245,7 @@ xaccAccountSetName (Account *acc, const char *str)
         return;
 
     xaccAccountBeginEdit(acc);
-    qof_string_cache_replace((void const **)(&priv->accountName), str);
+    priv->accountName = qof_string_cache_replace(priv->accountName, str);
     mark_account (acc);
     xaccAccountCommitEdit(acc);
 }
@@ -2264,7 +2264,7 @@ xaccAccountSetCode (Account *acc, const char *str)
         return;
 
     xaccAccountBeginEdit(acc);
-    qof_string_cache_replace((void const **)(&priv->accountCode), str ? str : "");
+    priv->accountCode = qof_string_cache_replace(priv->accountCode, str ? str : "");
     mark_account (acc);
     xaccAccountCommitEdit(acc);
 }
@@ -2283,7 +2283,7 @@ xaccAccountSetDescription (Account *acc, const char *str)
         return;
 
     xaccAccountBeginEdit(acc);
-    qof_string_cache_replace((void const **)(&priv->description), str ? str : "");
+    priv->description = qof_string_cache_replace(priv->description, str ? str : "");
     mark_account (acc);
     xaccAccountCommitEdit(acc);
 }
diff --git a/libgnucash/engine/qof-string-cache.cpp b/libgnucash/engine/qof-string-cache.cpp
index 7390a63..caba239 100644
--- a/libgnucash/engine/qof-string-cache.cpp
+++ b/libgnucash/engine/qof-string-cache.cpp
@@ -82,7 +82,7 @@ qof_string_cache_destroy (void)
 /* If the key exists in the cache, check the refcount.  If 1, just
  * remove the key.  Otherwise, decrement the refcount */
 void
-qof_string_cache_remove(gconstpointer key)
+qof_string_cache_remove(const char * key)
 {
     if (key)
     {
@@ -106,8 +106,8 @@ qof_string_cache_remove(gconstpointer key)
 
 /* If the key exists in the cache, increment the refcount.  Otherwise,
  * add it with a refcount of 1. */
-gpointer
-qof_string_cache_insert(gconstpointer key)
+char *
+qof_string_cache_insert(const char * key)
 {
     if (key)
     {
@@ -118,7 +118,7 @@ qof_string_cache_insert(gconstpointer key)
         {
             guint* refcount = (guint*)value;
             ++(*refcount);
-            return cache_key;
+            return static_cast <char *> (cache_key);
         }
         else
         {
@@ -126,17 +126,17 @@ qof_string_cache_insert(gconstpointer key)
             guint* refcount = static_cast<unsigned int*>(g_malloc(sizeof(guint)));
             *refcount = 1;
             g_hash_table_insert(cache, new_key, refcount);
-            return new_key;
+            return static_cast <char *> (new_key);
         }
     }
     return NULL;
 }
 
-void
-qof_string_cache_replace(gconstpointer * dst, gconstpointer src)
+char *
+qof_string_cache_replace(char const * dst, char const * src)
 {
-    gpointer tmp {qof_string_cache_insert(src)};
-    qof_string_cache_remove(&dst);
-    *dst = tmp;
+    char * tmp {qof_string_cache_insert (src)};
+    qof_string_cache_remove (dst);
+    return tmp;
 }
 /* ************************ END OF FILE ***************************** */
diff --git a/libgnucash/engine/qof-string-cache.h b/libgnucash/engine/qof-string-cache.h
index 2fd5274..f45ff1b 100644
--- a/libgnucash/engine/qof-string-cache.h
+++ b/libgnucash/engine/qof-string-cache.h
@@ -79,18 +79,18 @@ void qof_string_cache_destroy(void);
 /** You can use this function as a destroy notifier for a GHashTable
    that uses common strings as keys (or values, for that matter.)
 */
-void qof_string_cache_remove(gconstpointer key);
+void qof_string_cache_remove(const char * key);
 
 /** You can use this function with g_hash_table_insert(), for the key
    (or value), as long as you use the destroy notifier above.
 */
-gpointer qof_string_cache_insert(gconstpointer key);
+char * qof_string_cache_insert(const char * key);
 
 /** Same as CACHE_REPLACE below, but safe to call from C++.
  */
-void qof_string_cache_replace(gconstpointer * dst, gconstpointer src);
+char * qof_string_cache_replace(const char * dst, const char * src);
 
-#define CACHE_INSERT(str) qof_string_cache_insert((gconstpointer)(str))
+#define CACHE_INSERT(str) qof_string_cache_insert((str))
 #define CACHE_REMOVE(str) qof_string_cache_remove((str))
 
 /* Replace cached string currently in 'dst' with string in 'src'.
diff --git a/libgnucash/engine/qofbook.cpp b/libgnucash/engine/qofbook.cpp
index 15d8020..918e516 100644
--- a/libgnucash/engine/qofbook.cpp
+++ b/libgnucash/engine/qofbook.cpp
@@ -563,7 +563,7 @@ qof_book_get_collection (const QofBook *book, QofIdType entity_type)
         col = qof_collection_new (entity_type);
         g_hash_table_insert(
             book->hash_of_collections,
-            qof_string_cache_insert((gpointer) entity_type), col);
+            qof_string_cache_insert(entity_type), col);
     }
     return col;
 }

commit 805549ba247f79308f5e18e40f8999359dcc6e2a
Author: lmat <dartme18 at gmail.com>
Date:   Sun Dec 10 05:42:08 2017 -0800

    Rename qofinstance function
    
    This function was supposed to be renamed a while back. I had named it
    this way for debugging purposes.

diff --git a/libgnucash/engine/Scrub.c b/libgnucash/engine/Scrub.c
index b4b744b..f168a24 100644
--- a/libgnucash/engine/Scrub.c
+++ b/libgnucash/engine/Scrub.c
@@ -1228,10 +1228,10 @@ xaccAccountDeleteOldData (Account *account)
 {
     if (!account) return;
     xaccAccountBeginEdit (account);
-    qof_instance_set_var_kvp (QOF_INSTANCE (account), NULL, 1, "old-currency");
-    qof_instance_set_var_kvp (QOF_INSTANCE (account), NULL, 1, "old-security");
-    qof_instance_set_var_kvp (QOF_INSTANCE (account), NULL, 1, "old-currency-scu");
-    qof_instance_set_var_kvp (QOF_INSTANCE (account), NULL, 1, "old-security-scu");
+    qof_instance_set_kvp (QOF_INSTANCE (account), NULL, 1, "old-currency");
+    qof_instance_set_kvp (QOF_INSTANCE (account), NULL, 1, "old-security");
+    qof_instance_set_kvp (QOF_INSTANCE (account), NULL, 1, "old-currency-scu");
+    qof_instance_set_kvp (QOF_INSTANCE (account), NULL, 1, "old-security-scu");
     qof_instance_set_dirty (QOF_INSTANCE (account));
     xaccAccountCommitEdit (account);
 }
@@ -1337,7 +1337,7 @@ xaccAccountScrubKvp (Account *account)
 
     if (!account) return;
 
-    qof_instance_get_var_kvp (QOF_INSTANCE (account), &v, 1, "notes");
+    qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "notes");
     if (G_VALUE_HOLDS_STRING (&v))
     {
         str2 = g_strstrip(g_value_dup_string(&v));
@@ -1346,7 +1346,7 @@ xaccAccountScrubKvp (Account *account)
         g_free(str2);
     }
 
-    qof_instance_get_var_kvp (QOF_INSTANCE (account), &v, 1, "placeholder");
+    qof_instance_get_kvp (QOF_INSTANCE (account), &v, 1, "placeholder");
     if ((G_VALUE_HOLDS_STRING (&v) &&
         strcmp(g_value_get_string (&v), "false") == 0) ||
         (G_VALUE_HOLDS_BOOLEAN (&v) && ! g_value_get_boolean (&v)))
diff --git a/libgnucash/engine/Split.c b/libgnucash/engine/Split.c
index 772849f..452b36a 100644
--- a/libgnucash/engine/Split.c
+++ b/libgnucash/engine/Split.c
@@ -184,31 +184,31 @@ gnc_split_get_property(GObject         *object,
             g_value_take_object(value, split->lot);
             break;
         case PROP_SX_CREDIT_FORMULA:
-            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_FORMULA);
+            qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_FORMULA);
             break;
         case PROP_SX_CREDIT_NUMERIC:
-            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_NUMERIC);
+            qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_NUMERIC);
             break;
         case PROP_SX_DEBIT_FORMULA:
-            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_FORMULA);
+            qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_FORMULA);
             break;
         case PROP_SX_DEBIT_NUMERIC:
-            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_NUMERIC);
+            qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_NUMERIC);
             break;
         case PROP_SX_ACCOUNT:
-            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_ACCOUNT);
+            qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_ACCOUNT);
             break;
         case PROP_SX_SHARES:
-            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_SHARES);
+            qof_instance_get_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_SHARES);
             break;
         case PROP_ONLINE_ACCOUNT:
-            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 1, "online_id");
+            qof_instance_get_kvp (QOF_INSTANCE (split), value, 1, "online_id");
             break;
         case PROP_GAINS_SPLIT:
-            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 1, "gains-split");
+            qof_instance_get_kvp (QOF_INSTANCE (split), value, 1, "gains-split");
             break;
         case PROP_GAINS_SOURCE:
-            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 1, "gains-source");
+            qof_instance_get_kvp (QOF_INSTANCE (split), value, 1, "gains-source");
             break;
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -261,31 +261,31 @@ gnc_split_set_property(GObject         *object,
             xaccSplitSetLot(split, g_value_get_object(value));
             break;
         case PROP_SX_CREDIT_FORMULA:
-            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_FORMULA);
+            qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_FORMULA);
             break;
         case PROP_SX_CREDIT_NUMERIC:
-            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_NUMERIC);
+            qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_NUMERIC);
             break;
         case PROP_SX_DEBIT_FORMULA:
-            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_FORMULA);
+            qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_FORMULA);
             break;
         case PROP_SX_DEBIT_NUMERIC:
-            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_NUMERIC);
+            qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_NUMERIC);
             break;
         case PROP_SX_ACCOUNT:
-            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_ACCOUNT);
+            qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_ACCOUNT);
             break;
         case PROP_SX_SHARES:
-            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_SHARES);
+            qof_instance_set_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_SHARES);
             break;
         case PROP_ONLINE_ACCOUNT:
-            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 1, "online_id");
+            qof_instance_set_kvp (QOF_INSTANCE (split), value, 1, "online_id");
             break;
         case PROP_GAINS_SPLIT:
-            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 1, "gains-split");
+            qof_instance_set_kvp (QOF_INSTANCE (split), value, 1, "gains-split");
             break;
         case PROP_GAINS_SOURCE:
-            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 1, "gains-source");
+            qof_instance_set_kvp (QOF_INSTANCE (split), value, 1, "gains-source");
             break;
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -1079,7 +1079,7 @@ xaccSplitDetermineGainStatus (Split *split)
         return;
     }
 
-    qof_instance_get_var_kvp (QOF_INSTANCE (split), &v, 1, "gains-source");
+    qof_instance_get_kvp (QOF_INSTANCE (split), &v, 1, "gains-source");
     if (G_VALUE_HOLDS_BOXED (&v))
         guid = (GncGUID*)g_value_get_boxed (&v);
     if (!guid)
@@ -1972,7 +1972,7 @@ xaccSplitGetType(const Split *s)
     const char *split_type = NULL;
 
     if (!s) return NULL;
-    qof_instance_get_var_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
+    qof_instance_get_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
     if (G_VALUE_HOLDS_STRING (&v))
         split_type = g_value_get_string (&v);
     return split_type ? split_type : "normal";
@@ -1989,7 +1989,7 @@ xaccSplitMakeStockSplit(Split *s)
     s->value = gnc_numeric_zero();
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, "stock-split");
-    qof_instance_set_var_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
+    qof_instance_set_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
     SET_GAINS_VDIRTY(s);
     mark_split(s);
     qof_instance_set_dirty(QOF_INSTANCE(s));
@@ -2126,7 +2126,7 @@ xaccSplitVoidFormerAmount(const Split *split)
     GValue v = G_VALUE_INIT;
     gnc_numeric *num = NULL;
     g_return_val_if_fail(split, gnc_numeric_zero());
-    qof_instance_get_var_kvp (QOF_INSTANCE (split), &v, 1, void_former_amt_str);
+    qof_instance_get_kvp (QOF_INSTANCE (split), &v, 1, void_former_amt_str);
     if (G_VALUE_HOLDS_BOXED (&v))
         num = (gnc_numeric*)g_value_get_boxed (&v);
     return num ? *num : gnc_numeric_zero();
@@ -2138,7 +2138,7 @@ xaccSplitVoidFormerValue(const Split *split)
     GValue v = G_VALUE_INIT;
     gnc_numeric *num = NULL;
     g_return_val_if_fail(split, gnc_numeric_zero());
-    qof_instance_get_var_kvp (QOF_INSTANCE (split), &v, 1, void_former_val_str);
+    qof_instance_get_kvp (QOF_INSTANCE (split), &v, 1, void_former_val_str);
     if (G_VALUE_HOLDS_BOXED (&v))
         num = (gnc_numeric*)g_value_get_boxed (&v);
     return num ? *num : gnc_numeric_zero();
@@ -2153,10 +2153,10 @@ xaccSplitVoid(Split *split)
     g_value_init (&v, GNC_TYPE_NUMERIC);
     num =  xaccSplitGetAmount(split);
     g_value_set_boxed (&v, &num);
-    qof_instance_set_var_kvp (QOF_INSTANCE (split), &v, 1, void_former_amt_str);
+    qof_instance_set_kvp (QOF_INSTANCE (split), &v, 1, void_former_amt_str);
     num =  xaccSplitGetValue(split);
     g_value_set_boxed (&v, &num);
-    qof_instance_set_var_kvp (QOF_INSTANCE (split), &v, 1, void_former_val_str);
+    qof_instance_set_kvp (QOF_INSTANCE (split), &v, 1, void_former_val_str);
 
     /* Marking dirty handled by SetAmount etc. */
     xaccSplitSetAmount (split, zero);
@@ -2170,8 +2170,8 @@ xaccSplitUnvoid(Split *split)
     xaccSplitSetAmount (split, xaccSplitVoidFormerAmount(split));
     xaccSplitSetValue (split, xaccSplitVoidFormerValue(split));
     xaccSplitSetReconcile(split, NREC);
-    qof_instance_set_var_kvp (QOF_INSTANCE (split), NULL, 1, void_former_amt_str);
-    qof_instance_set_var_kvp (QOF_INSTANCE (split), NULL, 1, void_former_val_str);
+    qof_instance_set_kvp (QOF_INSTANCE (split), NULL, 1, void_former_amt_str);
+    qof_instance_set_kvp (QOF_INSTANCE (split), NULL, 1, void_former_val_str);
     qof_instance_set_dirty (QOF_INSTANCE (split));
 }
 
diff --git a/libgnucash/engine/Transaction.c b/libgnucash/engine/Transaction.c
index cfa651a..5fc7c7e 100644
--- a/libgnucash/engine/Transaction.c
+++ b/libgnucash/engine/Transaction.c
@@ -338,13 +338,13 @@ gnc_transaction_get_property(GObject* object,
         g_value_set_boxed(value, &tx->date_entered);
         break;
     case PROP_INVOICE:
-        qof_instance_get_var_kvp (QOF_INSTANCE (tx), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
+        qof_instance_get_kvp (QOF_INSTANCE (tx), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
         break;
     case PROP_SX_TXN:
-        qof_instance_get_var_kvp (QOF_INSTANCE (tx), value, 1, GNC_SX_FROM);
+        qof_instance_get_kvp (QOF_INSTANCE (tx), value, 1, GNC_SX_FROM);
         break;
     case PROP_ONLINE_ACCOUNT:
-        qof_instance_get_var_kvp (QOF_INSTANCE (tx), value, 1, "online_id");
+        qof_instance_get_kvp (QOF_INSTANCE (tx), value, 1, "online_id");
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -384,13 +384,13 @@ gnc_transaction_set_property(GObject* object,
         xaccTransSetDateEnteredTS(tx, g_value_get_boxed(value));
         break;
     case PROP_INVOICE:
-        qof_instance_set_var_kvp (QOF_INSTANCE (tx), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
+        qof_instance_set_kvp (QOF_INSTANCE (tx), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
         break;
     case PROP_SX_TXN:
-        qof_instance_set_var_kvp (QOF_INSTANCE (tx), value, 1, GNC_SX_FROM);
+        qof_instance_set_kvp (QOF_INSTANCE (tx), value, 1, GNC_SX_FROM);
         break;
     case PROP_ONLINE_ACCOUNT:
-        qof_instance_set_var_kvp (QOF_INSTANCE (tx), value, 1, "online_id");
+        qof_instance_set_kvp (QOF_INSTANCE (tx), value, 1, "online_id");
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -1987,7 +1987,7 @@ xaccTransSetDatePostedGDate (Transaction *trans, GDate date)
      * clearly be distinguished from the Timespec. */
     g_value_init (&v, G_TYPE_DATE);
     g_value_set_boxed (&v, &date);
-    qof_instance_set_var_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_DATE_POSTED);
+    qof_instance_set_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_DATE_POSTED);
     /* mark dirty and commit handled by SetDateInternal */
     xaccTransSetDateInternal(trans, &trans->date_posted,
                              gdate_to_timespec(date));
@@ -2063,7 +2063,7 @@ xaccTransSetDateDueTS (Transaction *trans, const Timespec *ts)
     g_value_init (&v, GNC_TYPE_TIMESPEC);
     g_value_set_boxed (&v, ts);
     xaccTransBeginEdit(trans);
-    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_DUE_KVP);
+    qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_DUE_KVP);
     qof_instance_set_dirty(QOF_INSTANCE(trans));
     xaccTransCommitEdit(trans);
 }
@@ -2077,7 +2077,7 @@ xaccTransSetTxnType (Transaction *trans, char type)
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, s);
     xaccTransBeginEdit(trans);
-    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_TXN_TYPE_KVP);
+    qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_TXN_TYPE_KVP);
     qof_instance_set_dirty(QOF_INSTANCE(trans));
     xaccTransCommitEdit(trans);
 }
@@ -2087,7 +2087,7 @@ void xaccTransClearReadOnly (Transaction *trans)
     if (trans)
     {
         xaccTransBeginEdit(trans);
-        qof_instance_set_var_kvp (QOF_INSTANCE (trans), NULL, 1, TRANS_READ_ONLY_REASON);
+        qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, TRANS_READ_ONLY_REASON);
         qof_instance_set_dirty(QOF_INSTANCE(trans));
         xaccTransCommitEdit(trans);
     }
@@ -2102,7 +2102,7 @@ xaccTransSetReadOnly (Transaction *trans, const char *reason)
         g_value_init (&v, G_TYPE_STRING);
         g_value_set_string (&v, reason);
         xaccTransBeginEdit(trans);
-        qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_READ_ONLY_REASON);
+        qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_READ_ONLY_REASON);
         qof_instance_set_dirty(QOF_INSTANCE(trans));
         xaccTransCommitEdit(trans);
     }
@@ -2160,7 +2160,7 @@ xaccTransSetAssociation (Transaction *trans, const char *assoc)
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, assoc);
     xaccTransBeginEdit(trans);
-    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, assoc_uri_str);
+    qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, assoc_uri_str);
     qof_instance_set_dirty(QOF_INSTANCE(trans));
     xaccTransCommitEdit(trans);
 }
@@ -2182,7 +2182,7 @@ xaccTransSetNotes (Transaction *trans, const char *notes)
     g_value_set_string (&v, notes);
     xaccTransBeginEdit(trans);
 
-    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
+    qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
     qof_instance_set_dirty(QOF_INSTANCE(trans));
     xaccTransCommitEdit(trans);
 }
@@ -2198,10 +2198,10 @@ xaccTransSetIsClosingTxn (Transaction *trans, gboolean is_closing)
         GValue v = G_VALUE_INIT;
         g_value_init (&v, G_TYPE_INT64);
         g_value_set_int64 (&v, 1);
-        qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_is_closing_str);
+        qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, trans_is_closing_str);
     }
     else
-        qof_instance_set_var_kvp (QOF_INSTANCE (trans), NULL, 1, trans_is_closing_str);
+        qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, trans_is_closing_str);
     qof_instance_set_dirty(QOF_INSTANCE(trans));
     xaccTransCommitEdit(trans);
 }
@@ -2336,7 +2336,7 @@ xaccTransGetAssociation (const Transaction *trans)
 {
     GValue v = G_VALUE_INIT;
     if (!trans) return NULL;
-    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, assoc_uri_str);
+    qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, assoc_uri_str);
     if (G_VALUE_HOLDS_STRING (&v))
          return g_value_get_string (&v);
     return NULL;
@@ -2347,7 +2347,7 @@ xaccTransGetNotes (const Transaction *trans)
 {
     GValue v = G_VALUE_INIT;
     if (!trans) return NULL;
-    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
+    qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
     if (G_VALUE_HOLDS_STRING (&v))
          return g_value_get_string (&v);
     return NULL;
@@ -2358,7 +2358,7 @@ xaccTransGetIsClosingTxn (const Transaction *trans)
 {
     GValue v = G_VALUE_INIT;
     if (!trans) return FALSE;
-    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_is_closing_str);
+    qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, trans_is_closing_str);
     if (G_VALUE_HOLDS_INT64 (&v))
          return g_value_get_int64 (&v);
     return FALSE;
@@ -2413,7 +2413,7 @@ xaccTransGetDatePostedGDate (const Transaction *trans)
          * from there because it doesn't suffer from time zone
          * shifts. */
         GValue v = G_VALUE_INIT;
-        qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_POSTED);
+        qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_POSTED);
         if (G_VALUE_HOLDS_BOXED (&v))
              result = *(GDate*)g_value_get_boxed (&v);
         if (! g_date_valid (&result))
@@ -2448,7 +2448,7 @@ xaccTransGetDateDueTS (const Transaction *trans, Timespec *ts)
     GValue v = G_VALUE_INIT;
     if (!trans || !ts) return;
 
-    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_DUE_KVP);
+    qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_DUE_KVP);
     if (G_VALUE_HOLDS_BOXED (&v))
          *ts = *(Timespec*)g_value_get_boxed (&v);
     if (ts->tv_sec == 0)
@@ -2470,7 +2470,7 @@ xaccTransGetTxnType (const Transaction *trans)
     GValue v = G_VALUE_INIT;
 
     if (!trans) return TXN_TYPE_NONE;
-    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_TXN_TYPE_KVP);
+    qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_TXN_TYPE_KVP);
     if (G_VALUE_HOLDS_STRING (&v))
          s = g_value_get_string (&v);
     if (s && strlen (s) == 1)
@@ -2488,7 +2488,7 @@ xaccTransGetReadOnly (const Transaction *trans)
     GValue v = G_VALUE_INIT;
     const char *s = NULL;
     if (trans == NULL) return NULL;
-    qof_instance_get_var_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_READ_ONLY_REASON);
+    qof_instance_get_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_READ_ONLY_REASON);
     if (G_VALUE_HOLDS_STRING (&v))
          s = g_value_get_string (&v);
     if (s && strlen (s))
@@ -2686,20 +2686,20 @@ xaccTransVoid(Transaction *trans, const char *reason)
         return;
     }
     xaccTransBeginEdit(trans);
-    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
+    qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
     if (G_VALUE_HOLDS_STRING (&v))
-        qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, void_former_notes_str);
+        qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, void_former_notes_str);
     else
         g_value_init (&v, G_TYPE_STRING);
 
     g_value_set_string (&v, _("Voided transaction"));
-    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
+    qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
     g_value_set_string (&v, reason);
-    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
+    qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
 
     gnc_timespec_to_iso8601_buff (timespec_now (), iso8601_str);
     g_value_set_string (&v, iso8601_str);
-    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, void_time_str);
+    qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, void_time_str);
 
     FOR_EACH_SPLIT(trans, xaccSplitVoid(s));
 
@@ -2715,7 +2715,7 @@ xaccTransGetVoidStatus(const Transaction *trans)
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(trans, FALSE);
 
-    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
+    qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
     if (G_VALUE_HOLDS_STRING (&v))
          s = g_value_get_string (&v);
     return s && strlen(s);
@@ -2727,7 +2727,7 @@ xaccTransGetVoidReason(const Transaction *trans)
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(trans, FALSE);
 
-    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
+    qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
     if (G_VALUE_HOLDS_STRING (&v))
          return g_value_get_string (&v);
     return NULL;
@@ -2741,7 +2741,7 @@ xaccTransGetVoidTime(const Transaction *tr)
     Timespec void_time = {0, 0};
 
     g_return_val_if_fail(tr, void_time);
-    qof_instance_get_var_kvp (QOF_INSTANCE (tr), &v, 1, void_time_str);
+    qof_instance_get_kvp (QOF_INSTANCE (tr), &v, 1, void_time_str);
     if (G_VALUE_HOLDS_STRING (&v))
         s = g_value_get_string (&v);
     if (s)
@@ -2756,18 +2756,18 @@ xaccTransUnvoid (Transaction *trans)
     const char *s = NULL;
     g_return_if_fail(trans);
 
-    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
+    qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
     if (G_VALUE_HOLDS_STRING (&v))
         s = g_value_get_string (&v);
     if (s == NULL) return; /* Transaction isn't voided. Bail. */
     xaccTransBeginEdit(trans);
 
-    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, void_former_notes_str);
+    qof_instance_get_kvp (QOF_INSTANCE (trans), &v, 1, void_former_notes_str);
     if (G_VALUE_HOLDS_STRING (&v))
-        qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
-    qof_instance_set_var_kvp (QOF_INSTANCE (trans), NULL, 1, void_former_notes_str);
-    qof_instance_set_var_kvp (QOF_INSTANCE (trans), NULL, 1, void_reason_str);
-    qof_instance_set_var_kvp (QOF_INSTANCE (trans), NULL, 1, void_time_str);
+        qof_instance_set_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
+    qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, void_former_notes_str);
+    qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, void_reason_str);
+    qof_instance_set_kvp (QOF_INSTANCE (trans), NULL, 1, void_time_str);
 
     FOR_EACH_SPLIT(trans, xaccSplitUnvoid(s));
 
@@ -2797,7 +2797,7 @@ xaccTransReverse (Transaction *orig)
     /* Now update the original with a pointer to the new one */
     g_value_init (&v, GNC_TYPE_GUID);
     g_value_set_boxed (&v, xaccTransGetGUID(trans));
-    qof_instance_set_var_kvp (QOF_INSTANCE (orig), &v, 1, TRANS_REVERSED_BY);
+    qof_instance_set_kvp (QOF_INSTANCE (orig), &v, 1, TRANS_REVERSED_BY);
 
     /* Make sure the reverse transaction is not read-only */
     xaccTransClearReadOnly(trans);
@@ -2812,7 +2812,7 @@ xaccTransGetReversedBy(const Transaction *trans)
 {
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(trans, NULL);
-    qof_instance_get_var_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_REVERSED_BY);
+    qof_instance_get_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_REVERSED_BY);
     if (G_VALUE_HOLDS_BOXED (&v))
         return xaccTransLookup((GncGUID*)g_value_get_boxed (&v),
                                qof_instance_get_book(trans));
diff --git a/libgnucash/engine/gnc-budget.c b/libgnucash/engine/gnc-budget.c
index 4da6cf1..a4a2a21 100644
--- a/libgnucash/engine/gnc-budget.c
+++ b/libgnucash/engine/gnc-budget.c
@@ -497,7 +497,7 @@ gnc_budget_unset_account_period_value(GncBudget *budget, const Account *account,
     make_period_path (account, period_num, path_part_one, path_part_two);
 
     gnc_budget_begin_edit(budget);
-    qof_instance_set_var_kvp (QOF_INSTANCE (budget), NULL, 2, path_part_one, path_part_two);
+    qof_instance_set_kvp (QOF_INSTANCE (budget), NULL, 2, path_part_one, path_part_two);
     qof_instance_set_dirty(&budget->inst);
     gnc_budget_commit_edit(budget);
 
@@ -529,13 +529,13 @@ gnc_budget_set_account_period_value(GncBudget *budget, const Account *account,
 
     gnc_budget_begin_edit(budget);
     if (gnc_numeric_check(val))
-        qof_instance_set_var_kvp (QOF_INSTANCE (budget), NULL, 2, path_part_one, path_part_two);
+        qof_instance_set_kvp (QOF_INSTANCE (budget), NULL, 2, path_part_one, path_part_two);
     else
     {
         GValue v = G_VALUE_INIT;
         g_value_init (&v, GNC_TYPE_NUMERIC);
         g_value_set_boxed (&v, &val);
-        qof_instance_set_var_kvp (QOF_INSTANCE (budget), &v, 2, path_part_one, path_part_two);
+        qof_instance_set_kvp (QOF_INSTANCE (budget), &v, 2, path_part_one, path_part_two);
     }
     qof_instance_set_dirty(&budget->inst);
     gnc_budget_commit_edit(budget);
@@ -561,7 +561,7 @@ gnc_budget_is_account_period_value_set(const GncBudget *budget,
     g_return_val_if_fail(account, FALSE);
 
     make_period_path (account, period_num, path_part_one, path_part_two);
-    qof_instance_get_var_kvp (QOF_INSTANCE (budget), &v, 2, path_part_one, path_part_two);
+    qof_instance_get_kvp (QOF_INSTANCE (budget), &v, 2, path_part_one, path_part_two);
     if (G_VALUE_HOLDS_BOXED (&v))
         ptr = g_value_get_boxed (&v);
     return (ptr != NULL);
@@ -581,7 +581,7 @@ gnc_budget_get_account_period_value(const GncBudget *budget,
     g_return_val_if_fail(account, gnc_numeric_zero());
 
     make_period_path (account, period_num, path_part_one, path_part_two);
-    qof_instance_get_var_kvp (QOF_INSTANCE (budget), &v, 2, path_part_one, path_part_two);
+    qof_instance_get_kvp (QOF_INSTANCE (budget), &v, 2, path_part_one, path_part_two);
     if (G_VALUE_HOLDS_BOXED (&v))
         numeric = (gnc_numeric*)g_value_get_boxed (&v);
 
diff --git a/libgnucash/engine/gnc-commodity.c b/libgnucash/engine/gnc-commodity.c
index 85570fb..c9c28ed 100644
--- a/libgnucash/engine/gnc-commodity.c
+++ b/libgnucash/engine/gnc-commodity.c
@@ -1083,7 +1083,7 @@ gnc_commodity_get_auto_quote_control_flag(const gnc_commodity *cm)
     GValue v = G_VALUE_INIT;
 
     if (!cm) return FALSE;
-    qof_instance_get_var_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
+    qof_instance_get_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
     if (G_VALUE_HOLDS_STRING (&v) &&
         strcmp(g_value_get_string (&v), "false") == 0)
         return FALSE;
@@ -1145,7 +1145,7 @@ gnc_commodity_get_user_symbol(const gnc_commodity *cm)
 {
     GValue v = G_VALUE_INIT;
     if (!cm) return NULL;
-    qof_instance_get_var_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
+    qof_instance_get_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
     if (G_VALUE_HOLDS_STRING (&v))
         return g_value_get_string (&v);
     return NULL;
@@ -1316,12 +1316,12 @@ gnc_commodity_set_auto_quote_control_flag(gnc_commodity *cm,
     }
     gnc_commodity_begin_edit(cm);
     if (flag)
-        qof_instance_set_var_kvp (QOF_INSTANCE (cm), NULL, 1, "auto_quote_control");
+        qof_instance_set_kvp (QOF_INSTANCE (cm), NULL, 1, "auto_quote_control");
     else
     {
         g_value_init (&v, G_TYPE_STRING);
         g_value_set_string (&v, "false");
-        qof_instance_set_var_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
+        qof_instance_set_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
     }
     mark_commodity_dirty(cm);
     gnc_commodity_commit_edit(cm);
@@ -1456,10 +1456,10 @@ gnc_commodity_set_user_symbol(gnc_commodity * cm, const char * user_symbol)
     {
         g_value_init (&v, G_TYPE_STRING);
         g_value_set_string (&v, user_symbol);
-        qof_instance_set_var_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
+        qof_instance_set_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
     }
     else
-        qof_instance_set_var_kvp (QOF_INSTANCE(cm), NULL, 1, "user_symbol");
+        qof_instance_set_kvp (QOF_INSTANCE(cm), NULL, 1, "user_symbol");
 
     mark_commodity_dirty(cm);
     gnc_commodity_commit_edit(cm);
diff --git a/libgnucash/engine/gnc-lot.c b/libgnucash/engine/gnc-lot.c
index 896a39d..7df4483 100644
--- a/libgnucash/engine/gnc-lot.c
+++ b/libgnucash/engine/gnc-lot.c
@@ -148,13 +148,13 @@ gnc_lot_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec*
         g_value_set_int(value, priv->marker);
         break;
     case PROP_INVOICE:
-        qof_instance_get_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
+        qof_instance_get_kvp (QOF_INSTANCE (lot), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
         break;
     case PROP_OWNER_TYPE:
-        qof_instance_get_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_TYPE);
+        qof_instance_get_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_TYPE);
         break;
     case PROP_OWNER_GUID:
-        qof_instance_get_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_GUID);
+        qof_instance_get_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_GUID);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -188,13 +188,13 @@ gnc_lot_set_property (GObject* object,
         priv->marker = g_value_get_int(value);
         break;
     case PROP_INVOICE:
-        qof_instance_set_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
+        qof_instance_set_kvp (QOF_INSTANCE (lot), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
         break;
     case PROP_OWNER_TYPE:
-        qof_instance_set_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_TYPE);
+        qof_instance_set_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_TYPE);
         break;
     case PROP_OWNER_GUID:
-        qof_instance_set_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_GUID);
+        qof_instance_set_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_GUID);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -427,7 +427,7 @@ gnc_lot_get_title (const GNCLot *lot)
 {
     GValue v = G_VALUE_INIT;
     if (!lot) return NULL;
-    qof_instance_get_var_kvp (QOF_INSTANCE (lot), &v, 1, "title");
+    qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "title");
     if (G_VALUE_HOLDS_STRING (&v))
         return g_value_get_string (&v);
     return NULL;
@@ -438,7 +438,7 @@ gnc_lot_get_notes (const GNCLot *lot)
 {
     GValue v = G_VALUE_INIT;
     if (!lot) return NULL;
-    qof_instance_get_var_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
+    qof_instance_get_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
     if (G_VALUE_HOLDS_STRING (&v))
         return g_value_get_string (&v);
     return NULL;
@@ -452,7 +452,7 @@ gnc_lot_set_title (GNCLot *lot, const char *str)
     qof_begin_edit(QOF_INSTANCE(lot));
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, str);
-    qof_instance_set_var_kvp (QOF_INSTANCE (lot), &v, 1, "title");
+    qof_instance_set_kvp (QOF_INSTANCE (lot), &v, 1, "title");
     qof_instance_set_dirty(QOF_INSTANCE(lot));
     gnc_lot_commit_edit(lot);
 }
@@ -465,7 +465,7 @@ gnc_lot_set_notes (GNCLot *lot, const char *str)
     qof_begin_edit(QOF_INSTANCE(lot));
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, str);
-    qof_instance_set_var_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
+    qof_instance_set_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
     qof_instance_set_dirty(QOF_INSTANCE(lot));
     gnc_lot_commit_edit(lot);
 }
diff --git a/libgnucash/engine/gncCustomer.c b/libgnucash/engine/gncCustomer.c
index b318e71..48b470f 100644
--- a/libgnucash/engine/gncCustomer.c
+++ b/libgnucash/engine/gncCustomer.c
@@ -140,13 +140,13 @@ gnc_customer_get_property (GObject         *object,
         g_value_set_string(value, cust->name);
         break;
     case PROP_PDF_DIRNAME:
-        qof_instance_get_var_kvp (QOF_INSTANCE (cust), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        qof_instance_get_kvp (QOF_INSTANCE (cust), value, 1, OWNER_EXPORT_PDF_DIRNAME);
         break;
     case PROP_LAST_POSTED:
-        qof_instance_get_var_kvp (QOF_INSTANCE (cust), value, 1, LAST_POSTED_TO_ACCT);
+        qof_instance_get_kvp (QOF_INSTANCE (cust), value, 1, LAST_POSTED_TO_ACCT);
         break;
     case PROP_PAYMENT_LAST_ACCT:
-        qof_instance_get_var_kvp (QOF_INSTANCE (cust), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        qof_instance_get_kvp (QOF_INSTANCE (cust), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -174,13 +174,13 @@ gnc_customer_set_property (GObject         *object,
         gncCustomerSetName(cust, g_value_get_string(value));
         break;
     case PROP_PDF_DIRNAME:
-        qof_instance_set_var_kvp (QOF_INSTANCE (cust), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        qof_instance_set_kvp (QOF_INSTANCE (cust), value, 1, OWNER_EXPORT_PDF_DIRNAME);
         break;
     case PROP_LAST_POSTED:
-        qof_instance_set_var_kvp (QOF_INSTANCE (cust), value, 1, LAST_POSTED_TO_ACCT);
+        qof_instance_set_kvp (QOF_INSTANCE (cust), value, 1, LAST_POSTED_TO_ACCT);
         break;
     case PROP_PAYMENT_LAST_ACCT:
-        qof_instance_set_var_kvp (QOF_INSTANCE (cust), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        qof_instance_set_kvp (QOF_INSTANCE (cust), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
diff --git a/libgnucash/engine/gncEmployee.c b/libgnucash/engine/gncEmployee.c
index f41c388..d992b0a 100644
--- a/libgnucash/engine/gncEmployee.c
+++ b/libgnucash/engine/gncEmployee.c
@@ -163,13 +163,13 @@ gnc_employee_get_property (GObject         *object,
         g_value_take_object(value, emp->ccard_acc);
         break;
     case PROP_PDF_DIRNAME:
-        qof_instance_get_var_kvp (QOF_INSTANCE (emp), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        qof_instance_get_kvp (QOF_INSTANCE (emp), value, 1, OWNER_EXPORT_PDF_DIRNAME);
         break;
     case PROP_LAST_POSTED:
-        qof_instance_get_var_kvp (QOF_INSTANCE (emp), value, 1, LAST_POSTED_TO_ACCT);
+        qof_instance_get_kvp (QOF_INSTANCE (emp), value, 1, LAST_POSTED_TO_ACCT);
         break;
     case PROP_PAYMENT_LAST_ACCT:
-        qof_instance_get_var_kvp (QOF_INSTANCE (emp), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        qof_instance_get_kvp (QOF_INSTANCE (emp), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -220,13 +220,13 @@ gnc_employee_set_property (GObject         *object,
         gncEmployeeSetCCard(emp, g_value_get_object(value));
         break;
     case PROP_PDF_DIRNAME:
-        qof_instance_set_var_kvp (QOF_INSTANCE (emp), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        qof_instance_set_kvp (QOF_INSTANCE (emp), value, 1, OWNER_EXPORT_PDF_DIRNAME);
         break;
     case PROP_LAST_POSTED:
-        qof_instance_set_var_kvp (QOF_INSTANCE (emp), value, 1, LAST_POSTED_TO_ACCT);
+        qof_instance_set_kvp (QOF_INSTANCE (emp), value, 1, LAST_POSTED_TO_ACCT);
         break;
     case PROP_PAYMENT_LAST_ACCT:
-        qof_instance_set_var_kvp (QOF_INSTANCE (emp), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        qof_instance_set_kvp (QOF_INSTANCE (emp), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
diff --git a/libgnucash/engine/gncInvoice.c b/libgnucash/engine/gncInvoice.c
index 074270d..ac8eaac 100644
--- a/libgnucash/engine/gncInvoice.c
+++ b/libgnucash/engine/gncInvoice.c
@@ -354,9 +354,9 @@ GncInvoice *gncInvoiceCopy (const GncInvoice *from)
     invoice->billing_id = CACHE_INSERT (from->billing_id);
     invoice->active = from->active;
 
-    qof_instance_get_var_kvp (QOF_INSTANCE (from), &v, 1, GNC_INVOICE_IS_CN);
+    qof_instance_get_kvp (QOF_INSTANCE (from), &v, 1, GNC_INVOICE_IS_CN);
     if (G_VALUE_HOLDS_INT64 (&v))
-         qof_instance_set_var_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_IS_CN);
+         qof_instance_set_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_IS_CN);
 
     invoice->terms = from->terms;
     gncBillTermIncRef (invoice->terms);
@@ -551,7 +551,7 @@ void gncInvoiceSetIsCreditNote (GncInvoice *invoice, gboolean credit_note)
     gncInvoiceBeginEdit (invoice);
     g_value_init (&v, G_TYPE_INT64);
     g_value_set_int64(&v, credit_note ? 1 : 0);
-    qof_instance_set_var_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_IS_CN);
+    qof_instance_set_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_IS_CN);
     mark_invoice (invoice);
     gncInvoiceCommitEdit (invoice);
 
@@ -1040,7 +1040,7 @@ gboolean gncInvoiceGetIsCreditNote (const GncInvoice *invoice)
 {
     GValue v = G_VALUE_INIT;
     if (!invoice) return FALSE;
-    qof_instance_get_var_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_IS_CN);
+    qof_instance_get_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_IS_CN);
     if (G_VALUE_HOLDS_INT64(&v) && g_value_get_int64(&v))
         return TRUE;
     else
diff --git a/libgnucash/engine/gncJob.c b/libgnucash/engine/gncJob.c
index 5d76c29..2ee97b7 100644
--- a/libgnucash/engine/gncJob.c
+++ b/libgnucash/engine/gncJob.c
@@ -120,7 +120,7 @@ gnc_job_get_property (GObject         *object,
         g_value_set_string(value, job->name);
         break;
     case PROP_PDF_DIRNAME:
-        qof_instance_get_var_kvp (QOF_INSTANCE (job), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        qof_instance_get_kvp (QOF_INSTANCE (job), value, 1, OWNER_EXPORT_PDF_DIRNAME);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -148,7 +148,7 @@ gnc_job_set_property (GObject         *object,
         gncJobSetName(job, g_value_get_string(value));
         break;
     case PROP_PDF_DIRNAME:
-        qof_instance_set_var_kvp (QOF_INSTANCE (job), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        qof_instance_set_kvp (QOF_INSTANCE (job), value, 1, OWNER_EXPORT_PDF_DIRNAME);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -316,11 +316,11 @@ void gncJobSetRate (GncJob *job, gnc_numeric rate)
         GValue v = G_VALUE_INIT;
         g_value_init (&v, GNC_TYPE_NUMERIC);
         g_value_set_boxed (&v, &rate);
-        qof_instance_set_var_kvp (QOF_INSTANCE (job), &v, 1, GNC_JOB_RATE);
+        qof_instance_set_kvp (QOF_INSTANCE (job), &v, 1, GNC_JOB_RATE);
     }
     else
     {
-        qof_instance_set_var_kvp (QOF_INSTANCE (job), NULL, 1, GNC_JOB_RATE);
+        qof_instance_set_kvp (QOF_INSTANCE (job), NULL, 1, GNC_JOB_RATE);
     }
     mark_job (job);
     gncJobCommitEdit (job);
@@ -454,7 +454,7 @@ gnc_numeric gncJobGetRate (const GncJob *job)
     GValue v = G_VALUE_INIT;
     gnc_numeric *rate = NULL;
     if (!job) return gnc_numeric_zero ();
-    qof_instance_get_var_kvp (QOF_INSTANCE (job), &v, 1, GNC_JOB_RATE);
+    qof_instance_get_kvp (QOF_INSTANCE (job), &v, 1, GNC_JOB_RATE);
     if (G_VALUE_HOLDS_BOXED (&v))
         rate = (gnc_numeric*)g_value_get_boxed (&v);
     if (rate)
diff --git a/libgnucash/engine/gncVendor.c b/libgnucash/engine/gncVendor.c
index 1df3fab..b5f418c 100644
--- a/libgnucash/engine/gncVendor.c
+++ b/libgnucash/engine/gncVendor.c
@@ -179,13 +179,13 @@ gnc_vendor_get_property (GObject         *object,
         g_value_set_string(value, qofVendorGetTaxIncluded(vendor));
         break;
     case PROP_PDF_DIRNAME:
-        qof_instance_get_var_kvp (QOF_INSTANCE (vendor), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        qof_instance_get_kvp (QOF_INSTANCE (vendor), value, 1, OWNER_EXPORT_PDF_DIRNAME);
         break;
     case PROP_LAST_POSTED:
-        qof_instance_get_var_kvp (QOF_INSTANCE (vendor), value, 1, LAST_POSTED_TO_ACCT);
+        qof_instance_get_kvp (QOF_INSTANCE (vendor), value, 1, LAST_POSTED_TO_ACCT);
         break;
     case PROP_PAYMENT_LAST_ACCT:
-        qof_instance_get_var_kvp (QOF_INSTANCE (vendor), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        qof_instance_get_kvp (QOF_INSTANCE (vendor), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -243,13 +243,13 @@ gnc_vendor_set_property (GObject         *object,
         qofVendorSetTaxIncluded(vendor, g_value_get_string(value));
         break;
     case PROP_PDF_DIRNAME:
-        qof_instance_set_var_kvp (QOF_INSTANCE (vendor), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        qof_instance_set_kvp (QOF_INSTANCE (vendor), value, 1, OWNER_EXPORT_PDF_DIRNAME);
         break;
     case PROP_LAST_POSTED:
-        qof_instance_set_var_kvp (QOF_INSTANCE (vendor), value, 1, LAST_POSTED_TO_ACCT);
+        qof_instance_set_kvp (QOF_INSTANCE (vendor), value, 1, LAST_POSTED_TO_ACCT);
         break;
     case PROP_PAYMENT_LAST_ACCT:
-        qof_instance_set_var_kvp (QOF_INSTANCE (vendor), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        qof_instance_set_kvp (QOF_INSTANCE (vendor), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
diff --git a/libgnucash/engine/qofinstance-p.h b/libgnucash/engine/qofinstance-p.h
index c0d79f9..102af1e 100644
--- a/libgnucash/engine/qofinstance-p.h
+++ b/libgnucash/engine/qofinstance-p.h
@@ -124,7 +124,7 @@ gboolean qof_instance_has_kvp (QofInstance *inst);
  * @param value: A GValue containing an item of a type which KvpValue knows
  *           how to store.
  */
-void qof_instance_set_var_kvp (QofInstance *, GValue const * value, unsigned count, ...);
+void qof_instance_set_kvp (QofInstance *, GValue const * value, unsigned count, ...);
 
 /** Retrieves the contents of a KVP slot into a provided GValue.
  * @param inst: The QofInstance
@@ -132,7 +132,7 @@ void qof_instance_set_var_kvp (QofInstance *, GValue const * value, unsigned cou
  * @param value: A GValue into which to store the value of the slot. It will be
  *               set to the correct type.
  */
-void qof_instance_get_var_kvp (QofInstance *, GValue * value, unsigned count, ...);
+void qof_instance_get_kvp (QofInstance *, GValue * value, unsigned count, ...);
 
 /** @} Close out the DOxygen ingroup */
 /* Functions to isolate the KVP mechanism inside QOF for cases where
diff --git a/libgnucash/engine/qofinstance.cpp b/libgnucash/engine/qofinstance.cpp
index 57cc6bd..e82980c 100644
--- a/libgnucash/engine/qofinstance.cpp
+++ b/libgnucash/engine/qofinstance.cpp
@@ -1066,7 +1066,7 @@ void qof_instance_set_path_kvp (QofInstance * inst, GValue const * value, std::v
 }
 
 void
-qof_instance_set_var_kvp (QofInstance * inst, GValue const * value, unsigned count, ...)
+qof_instance_set_kvp (QofInstance * inst, GValue const * value, unsigned count, ...)
 {
     std::vector<std::string> path;
     va_list args;
@@ -1091,7 +1091,7 @@ void qof_instance_get_path_kvp (QofInstance * inst, GValue * value, std::vector<
 }
 
 void
-qof_instance_get_var_kvp (QofInstance * inst, GValue * value, unsigned count, ...)
+qof_instance_get_kvp (QofInstance * inst, GValue * value, unsigned count, ...)
 {
     std::vector<std::string> path;
     va_list args;

commit fbf4843f31b69eb588d6b47978aa1b8b2265324d
Author: lmat <dartme18 at gmail.com>
Date:   Sat Dec 9 19:49:03 2017 -0800

    Changed bayes import map design
    
    This commit introduces a new feature flag:
    GNC_FEATURE_GUID_FLAT_BAYESIAN. It signifies that the bayes import map
    data are stored flat and by guid. Any time bayes import map data are
    accessed, they are converted if necessary.

diff --git a/gnucash/gnome-utils/gnc-file.c b/gnucash/gnome-utils/gnc-file.c
index 12d5e59..aa88b28 100644
--- a/gnucash/gnome-utils/gnc-file.c
+++ b/gnucash/gnome-utils/gnc-file.c
@@ -1022,12 +1022,6 @@ RESTART:
         gnc_warning_dialog(NULL, "%s", message);
         g_free ( message );
     }
-
-    // Convert imap mappings from account full name to guid strings
-    qof_event_suspend();
-    gnc_account_imap_convert_bayes (gnc_get_current_book());
-    qof_event_resume();
-
     return TRUE;
 }
 
diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 67692b3..f04c43a 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -5270,6 +5270,160 @@ get_first_pass_probabilities(GncImportMatchMap * imap, GList * tokens)
     return ret;
 }
 
+static std::string
+look_for_old_separator_descendants (Account *root, std::string const & full_name, const gchar *separator)
+{
+    GList *top_accounts, *ptr;
+    gint   found_len = 0;
+    gchar  found_sep;
+    top_accounts = gnc_account_get_descendants (root);
+    PINFO("Incoming full_name is '%s', current separator is '%s'", full_name.c_str (), separator);
+    /* Go through list of top level accounts */
+    for (ptr = top_accounts; ptr; ptr = g_list_next (ptr))
+    {
+        const gchar *name = xaccAccountGetName (static_cast <Account const *> (ptr->data));
+        // we are looking for the longest top level account that matches
+        if (g_str_has_prefix (full_name.c_str (), name))
+        {
+            gint name_len = strlen (name);
+            const gchar old_sep = full_name[name_len];
+            if (!g_ascii_isalnum (old_sep)) // test for non alpha numeric
+            {
+                if (name_len > found_len)
+                {
+                    found_sep = full_name[name_len];
+                    found_len = name_len;
+                }
+            }
+        }
+    }
+    g_list_free (top_accounts); // Free the List
+    std::string new_name {full_name};
+    if (found_len > 1)
+        std::replace (new_name.begin (), new_name.end (), found_sep, *separator);
+    PINFO ("Return full_name is '%s'", new_name.c_str ());
+    return new_name;
+}
+
+static std::string
+get_guid_from_account_name (Account * root, std::string const & name)
+{
+    auto map_account = gnc_account_lookup_by_full_name (root, name.c_str ());
+    if (!map_account)
+    {
+        auto temp_account_name = look_for_old_separator_descendants (root, name,
+             gnc_get_account_separator_string ());
+        map_account = gnc_account_lookup_by_full_name (root, temp_account_name.c_str ());
+    }
+    auto temp_guid = gnc::GUID {*xaccAccountGetGUID (map_account)};
+    return temp_guid.to_string ();
+}
+
+static FlatKvpEntry
+convert_entry (KvpEntry entry, Account* root)
+{
+    /*We need to make a copy here.*/
+    auto account_name = entry.first.back();
+    if (!gnc::GUID::is_valid_guid (account_name))
+    {
+        /* Earlier version stored the account name in the import map, and
+         * there were early beta versions of 2.7 that stored a GUID.
+         * If there is no GUID, we assume it's an account name. */
+        /* Take off the account name and replace it with the GUID */
+        entry.first.pop_back();
+        auto guid_str = get_guid_from_account_name (root, account_name);
+        entry.first.emplace_back (guid_str);
+    }
+    std::string new_key {std::accumulate (entry.first.begin(), entry.first.end(), std::string {})};
+    new_key = IMAP_FRAME_BAYES + new_key;
+    return {new_key, entry.second};
+}
+
+static std::vector<FlatKvpEntry>
+get_new_flat_imap (Account * acc)
+{
+    auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
+    auto slot = frame->get_slot ({IMAP_FRAME_BAYES});
+    if (!slot)
+        return {};
+    auto imap_frame = slot->get<KvpFrame*> ();
+    auto flat_kvp = imap_frame->flatten_kvp ();
+    auto root = gnc_account_get_root (acc);
+    std::vector <FlatKvpEntry> ret;
+    for (auto const & flat_entry : flat_kvp)
+    {
+        auto converted_entry = convert_entry (flat_entry, root);
+        /*If the entry was invalid, we don't perpetuate it.*/
+        if (converted_entry.first.size())
+            ret.emplace_back (converted_entry);
+    }
+    return ret;
+}
+
+static bool
+convert_imap_account_bayes_to_flat (Account *acc)
+{
+    auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
+    if (!frame->get_keys().size())
+        return false;
+    auto new_imap = get_new_flat_imap(acc);
+    xaccAccountBeginEdit(acc);
+    frame->set({IMAP_FRAME_BAYES}, nullptr);
+    if (!new_imap.size ())
+    {
+        xaccAccountCommitEdit(acc);
+        return false;
+    }
+    std::for_each(new_imap.begin(), new_imap.end(), [&frame] (FlatKvpEntry const & entry) {
+        frame->set({entry.first.c_str()}, entry.second);
+    });
+    qof_instance_set_dirty (QOF_INSTANCE (acc));
+    xaccAccountCommitEdit(acc);
+    return true;
+}
+
+/*
+ * Checks for import map data and converts them when found.
+ */
+static bool
+imap_convert_bayes_to_flat (QofBook * book)
+{
+    auto root = gnc_book_get_root_account (book);
+    auto accts = gnc_account_get_descendants_sorted (root);
+    bool ret = false;
+    for (auto ptr = accts; ptr; ptr = g_list_next (ptr))
+    {
+        Account *acc = static_cast <Account*> (ptr->data);
+        if (convert_imap_account_bayes_to_flat (acc))
+        {
+            ret = true;
+            gnc_features_set_used (book, GNC_FEATURE_GUID_FLAT_BAYESIAN);
+        }
+    }
+    g_list_free (accts);
+    return ret;
+}
+
+/*
+ * Here we check to see the state of import map data.
+ *
+ * If the GUID_FLAT_BAYESIAN feature flag is set, everything
+ * should be fine.
+ *
+ * If it is not set, there are two possibilities: import data
+ * are present from a previous version or not. If they are,
+ * they are converted, and the feature flag set. If there are
+ * no previous data, nothing is done.
+ */
+static void
+check_import_map_data (QofBook *book)
+{
+    if (gnc_features_check_used (book, GNC_FEATURE_GUID_FLAT_BAYESIAN))
+        return;
+    /* This function will set GNC_FEATURE_GUID_FLAT_BAYESIAN if necessary.*/
+    imap_convert_bayes_to_flat (book);
+}
+
 static constexpr double threshold = .90 * probability_factor; /* 90% */
 
 /** Look up an Account in the map */
@@ -5278,6 +5432,7 @@ gnc_account_imap_find_account_bayes (GncImportMatchMap *imap, GList *tokens)
 {
     if (!imap)
         return nullptr;
+    check_import_map_data (imap->book);
     auto first_pass = get_first_pass_probabilities(imap, tokens);
     if (!first_pass.size())
         return nullptr;
@@ -5330,7 +5485,7 @@ change_imap_entry (GncImportMatchMap *imap, std::string const & path, int64_t to
 
     // Add or Update the entry based on guid
     qof_instance_set_path_kvp (QOF_INSTANCE (imap->acc), &value, {path});
-    gnc_features_set_used (imap->book, GNC_FEATURE_GUID_BAYESIAN);
+    gnc_features_set_used (imap->book, GNC_FEATURE_GUID_FLAT_BAYESIAN);
 }
 
 /** Updates the imap for a given account using a list of tokens */
@@ -5350,6 +5505,7 @@ gnc_account_imap_add_account_bayes (GncImportMatchMap *imap,
         LEAVE(" ");
         return;
     }
+    check_import_map_data (imap->book);
 
     g_return_if_fail (acc != NULL);
     account_fullname = gnc_account_get_full_name(acc);
@@ -5462,6 +5618,7 @@ build_bayes (const char *key, KvpValue * value, GncImapInfo & imapInfo)
 GList *
 gnc_account_imap_get_info_bayes (Account *acc)
 {
+    check_import_map_data (gnc_account_get_book (acc));
     /* A dummy object which is used to hold the specified account, and the list
      * of data about which we care. */
     GncImapInfo imapInfo {acc, nullptr};
@@ -5533,151 +5690,6 @@ gnc_account_delete_map_entry (Account *acc, char *full_category, gboolean empty)
     g_free (full_category);
 }
 
-/*******************************************************************************/
-
-static std::string
-look_for_old_separator_descendants (Account *root, std::string const & full_name, const gchar *separator)
-{
-    GList *top_accounts, *ptr;
-    gint   found_len = 0;
-    gchar  found_sep;
-    top_accounts = gnc_account_get_descendants (root);
-    PINFO("Incoming full_name is '%s', current separator is '%s'", full_name.c_str (), separator);
-    /* Go through list of top level accounts */
-    for (ptr = top_accounts; ptr; ptr = g_list_next (ptr))
-    {
-        const gchar *name = xaccAccountGetName (static_cast <Account const *> (ptr->data));
-        // we are looking for the longest top level account that matches
-        if (g_str_has_prefix (full_name.c_str (), name))
-        {
-            gint name_len = strlen (name);
-            const gchar old_sep = full_name[name_len];
-            if (!g_ascii_isalnum (old_sep)) // test for non alpha numeric
-            {
-                if (name_len > found_len)
-                {
-                    found_sep = full_name[name_len];
-                    found_len = name_len;
-                }
-            }
-        }
-    }
-    g_list_free (top_accounts); // Free the List
-    std::string new_name {full_name};
-    if (found_len > 1)
-        std::replace (new_name.begin (), new_name.end (), found_sep, *separator);
-    PINFO("Return full_name is '%s'", new_name);
-    return new_name;
-}
-
-static std::string
-get_guid_from_account_name (Account * root, std::string const & name)
-{
-    auto map_account = gnc_account_lookup_by_full_name (root, name.c_str ());
-    if (!map_account)
-    {
-        auto temp_account_name = look_for_old_separator_descendants (root, name,
-             gnc_get_account_separator_string ());
-        map_account = gnc_account_lookup_by_full_name (root, temp_account_name.c_str ());
-    }
-    auto temp_guid = gnc::GUID {*xaccAccountGetGUID (map_account)};
-    return temp_guid.to_string ();
-}
-
-static FlatKvpEntry
-convert_entry (KvpEntry entry, Account* root)
-{
-    /*We need to make a copy here.*/
-    auto account_name = entry.first.back();
-    entry.first.pop_back();
-    auto guid_str = get_guid_from_account_name (root, account_name);
-    entry.first.emplace_back ("/");
-    entry.first.emplace_back (guid_str);
-    std::string new_key {std::accumulate (entry.first.begin(), entry.first.end(), std::string {})};
-    new_key = IMAP_FRAME_BAYES + new_key;
-    return {new_key, entry.second};
-}
-
-static std::vector<FlatKvpEntry>
-get_new_guid_imap (Account * acc)
-{
-    auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
-    auto slot = frame->get_slot ({IMAP_FRAME_BAYES});
-    if (!slot)
-        return {};
-    auto imap_frame = slot->get<KvpFrame*> ();
-    auto flat_kvp = imap_frame->flatten_kvp ();
-    auto root = gnc_account_get_root (acc);
-    std::vector <FlatKvpEntry> ret;
-    for (auto const & flat_entry : flat_kvp)
-        ret.emplace_back (convert_entry (flat_entry, root));
-    return ret;
-}
-
-static bool
-convert_imap_account_bayes_to_guid (Account *acc)
-{
-    auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
-    if (!frame->get_keys().size())
-        return false;
-    auto new_imap = get_new_guid_imap(acc);
-    xaccAccountBeginEdit(acc);
-    frame->set({IMAP_FRAME_BAYES}, nullptr);
-    if (!new_imap.size ())
-    {
-        xaccAccountCommitEdit(acc);
-        return false;
-    }
-    std::for_each(new_imap.begin(), new_imap.end(), [&frame] (FlatKvpEntry const & entry) {
-        frame->set({entry.first.c_str()}, entry.second);
-    });
-    qof_instance_set_dirty (QOF_INSTANCE (acc));
-    xaccAccountCommitEdit(acc);
-    return true;
-}
-
-char const * run_once_key_to_guid {"changed-bayesian-to-guid"};
-
-static void
-imap_convert_bayes_to_guid (QofBook * book)
-{
-    auto root = gnc_book_get_root_account (book);
-    auto accts = gnc_account_get_descendants_sorted (root);
-    for (auto ptr = accts; ptr; ptr = g_list_next (ptr))
-    {
-        Account *acc = static_cast <Account*> (ptr->data);
-        if (convert_imap_account_bayes_to_guid (acc))
-            gnc_features_set_used (book, GNC_FEATURE_GUID_BAYESIAN);
-    }
-    g_list_free (accts);
-}
-
-static bool
-run_once_key_set (char const * key, QofBook * book)
-{
-    GValue value G_VALUE_INIT;
-    qof_instance_get_path_kvp (QOF_INSTANCE(book), &value, {key});
-    return G_VALUE_HOLDS_STRING(&value) && strcmp(g_value_get_string(&value), "true");
-}
-
-static void
-set_run_once_key (char const * key, QofBook * book)
-{
-    GValue value G_VALUE_INIT;
-    g_value_init(&value, G_TYPE_BOOLEAN);
-    g_value_set_boolean(&value, TRUE);
-    qof_instance_set_path_kvp(QOF_INSTANCE (book), &value, {key});
-}
-
-void
-gnc_account_imap_convert_bayes (QofBook *book)
-{
-    if (run_once_key_set (run_once_key_to_guid, book))
-        return;
-    imap_convert_bayes_to_guid (book);
-    set_run_once_key (run_once_key_to_guid, book);
-}
-
 /* ================================================================ */
 /* QofObject function implementation and registration */
 
diff --git a/libgnucash/engine/Account.h b/libgnucash/engine/Account.h
index 2f80632..477d406 100644
--- a/libgnucash/engine/Account.h
+++ b/libgnucash/engine/Account.h
@@ -1449,11 +1449,6 @@ gchar *gnc_account_get_map_entry (Account *acc, const char *full_category);
  */
 void gnc_account_delete_map_entry (Account *acc, char *full_category, gboolean empty);
 
-/** Search for Bayesian entries with mappings based on full account name and change
- *  them to be based on the account guid
- */
-void gnc_account_imap_convert_bayes (QofBook *book);
-
 /** @} */
 
 
diff --git a/libgnucash/engine/gnc-features.c b/libgnucash/engine/gnc-features.c
index f125602..0c58bad 100644
--- a/libgnucash/engine/gnc-features.c
+++ b/libgnucash/engine/gnc-features.c
@@ -46,6 +46,7 @@ static gncFeature known_features[] =
     { GNC_FEATURE_KVP_EXTRA_DATA, "Extra data for addresses, jobs or invoice entries (requires at least GnuCash 2.6.4)" },
     { GNC_FEATURE_BOOK_CURRENCY, "User specifies a 'book-currency'; costs of other currencies/commodities tracked in terms of book-currency (requires at least GnuCash 2.7.0)" },
     { GNC_FEATURE_GUID_BAYESIAN, "Use account GUID as key for Bayesian data (requires at least GnuCash 2.6.12)" },
+    { GNC_FEATURE_GUID_FLAT_BAYESIAN, "Use account GUID as key for bayesian data and store KVP flat" },
     { NULL },
 };
 
@@ -148,6 +149,32 @@ void gnc_features_set_used (QofBook *book, const gchar *feature)
     }
 
     qof_book_set_feature (book, feature, description);
+}
 
+struct CheckFeature
+{
+    gchar const * checked_feature;
+    gboolean found;
+};
 
+static void gnc_features_check_feature_cb (gpointer pkey, gpointer value,
+				  gpointer data)
+{
+    const gchar *key = (const gchar*)pkey;
+    struct CheckFeature * check_data = data;
+    g_assert(data);
+    if (!g_strcmp0 (key, check_data->checked_feature))
+        check_data->found = TRUE;
 }
+
+gboolean gnc_features_check_used (QofBook *book, const gchar * feature)
+{
+    GHashTable *features_used = qof_book_get_features (book);
+    struct CheckFeature check_data = {feature, FALSE};
+    /* Setup the known_features hash table */
+    gnc_features_init();
+    g_hash_table_foreach (features_used, &gnc_features_check_feature_cb, &check_data);
+    g_hash_table_unref (features_used);
+    return check_data.found;
+}
+
diff --git a/libgnucash/engine/gnc-features.h b/libgnucash/engine/gnc-features.h
index feefe8d..2beca42 100644
--- a/libgnucash/engine/gnc-features.h
+++ b/libgnucash/engine/gnc-features.h
@@ -50,6 +50,7 @@ extern "C" {
 #define GNC_FEATURE_KVP_EXTRA_DATA "Extra data in addresses, jobs or invoice entries"
 #define GNC_FEATURE_BOOK_CURRENCY "Use a Book-Currency"
 #define GNC_FEATURE_GUID_BAYESIAN "Account GUID based Bayesian data"
+#define GNC_FEATURE_GUID_FLAT_BAYESIAN "Account GUID based bayesian with flat KVP"
 
 /** @} */
 
@@ -68,10 +69,14 @@ gchar *gnc_features_test_unknown (QofBook *book);
  */
 void gnc_features_set_used (QofBook *book, const gchar *feature);
 
+/*
+ * Returns true if the specified feature is used.
+ */
+gboolean gnc_features_check_used (QofBook *, char const * feature);
+
 #ifdef __cplusplus
 } /* extern "C" */
-#endif
-
+#endif /*__cplusplus*/
 #endif /* GNC_FEATURES_H */
 /** @} */
 /** @} */
diff --git a/libgnucash/engine/kvp-frame.cpp b/libgnucash/engine/kvp-frame.cpp
index 6f0fc4a..3d09e2f 100644
--- a/libgnucash/engine/kvp-frame.cpp
+++ b/libgnucash/engine/kvp-frame.cpp
@@ -427,16 +427,15 @@ KvpFrame::flatten_kvp_impl(std::vector <std::string> path, std::vector <KvpEntry
 {
     for (auto const & entry : m_valuemap)
     {
+        std::vector<std::string> new_path {path};
+        new_path.push_back("/");
         if (entry.second->get_type() == KvpValue::Type::FRAME)
         {
-            std::vector<std::string> send_path {path};
-            send_path.push_back("/");
-            send_path.push_back(entry.first);
-            entry.second->get<KvpFrame*>()->flatten_kvp_impl(send_path, entries);
+            new_path.push_back(entry.first);
+            entry.second->get<KvpFrame*>()->flatten_kvp_impl(new_path, entries);
         }
         else
         {
-            std::vector <std::string> new_path {path};
             new_path.emplace_back (entry.first);
             entries.emplace_back (new_path, entry.second);
         }
diff --git a/libgnucash/engine/qofbook.cpp b/libgnucash/engine/qofbook.cpp
index 82f998e..15d8020 100644
--- a/libgnucash/engine/qofbook.cpp
+++ b/libgnucash/engine/qofbook.cpp
@@ -1076,7 +1076,7 @@ static void
 add_feature_to_hash (const gchar *key, KvpValue *value, GHashTable * user_data)
 {
     gchar *descr = g_strdup(value->get<const char*>());
-    g_hash_table_insert (*(GHashTable**)user_data, (gchar*)key, descr);
+    g_hash_table_insert (user_data, (gchar*)key, descr);
 }
 
 GHashTable *
diff --git a/libgnucash/engine/test/gtest-import-map.cpp b/libgnucash/engine/test/gtest-import-map.cpp
index df72445..4f6c7cd 100644
--- a/libgnucash/engine/test/gtest-import-map.cpp
+++ b/libgnucash/engine/test/gtest-import-map.cpp
@@ -318,13 +318,8 @@ TEST_F(ImapBayesTest, AddAccountBayes)
     EXPECT_EQ(2, value->get<int64_t>());
 }
 
-TEST_F(ImapBayesTest, ConvertAccountBayes)
+TEST_F(ImapBayesTest, ConvertBayesData)
 {
-    // prevent the embedded beginedit/committedit from doing anything
-    qof_instance_increase_editlevel(QOF_INSTANCE(t_bank_account));
-    qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
-    gnc_account_imap_add_account_bayes(t_imap, t_list1, t_expense_account1); //Food
-    gnc_account_imap_add_account_bayes(t_imap, t_list2, t_expense_account2); //Drink
     auto root = qof_instance_get_slots(QOF_INSTANCE(t_bank_account));
     auto book = qof_instance_get_slots(QOF_INSTANCE(t_imap->book));
     auto acct1_guid = guid_to_string (xaccAccountGetGUID(t_expense_account1)); //Food
@@ -334,15 +329,6 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
     auto val1 = new KvpValue(static_cast<int64_t>(10));
     auto val2 = new KvpValue(static_cast<int64_t>(5));
     auto val3 = new KvpValue(static_cast<int64_t>(2));
-    // Test for existing entries, all will be 1
-    auto value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + acct1_guid});
-    EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + bar + "/" + acct1_guid});
-    EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + baz + "/" + acct2_guid});
-    EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + waldo + "/" + acct2_guid});
-    EXPECT_EQ(1, value->get<int64_t>());
     // Set up some old entries
     root->set_path({IMAP_FRAME_BAYES, "severely", "divided", "token", "Asset-Bank"}, val1);
     root->set_path({IMAP_FRAME_BAYES, salt, "Asset-Bank#Bank"}, new KvpValue{*val1});
@@ -350,13 +336,11 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
     root->set_path({IMAP_FRAME_BAYES, pork, "Expense#Food"}, new KvpValue{*val2});
     root->set_path({IMAP_FRAME_BAYES, sausage, "Expense#Drink"}, val3);
     root->set_path({IMAP_FRAME_BAYES, foo, "Expense#Food"}, new KvpValue{*val2});
-    EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account)));
-    EXPECT_TRUE(qof_instance_get_dirty_flag(QOF_INSTANCE(t_bank_account)));
-    qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
-    // Start Convert
-    gnc_account_imap_convert_bayes (t_imap->book);
+    root->set_path({IMAP_FRAME_BAYES, salt, acct1_guid}, new KvpValue{*val1});
+    /*Calling into the imap functions should trigger a conversion.*/
+    gnc_account_imap_add_account_bayes(t_imap, t_list5, t_expense_account2); //pork and sausage; account Food
     // convert from 'Asset-Bank' to 'Asset-Bank' guid
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/severely/divided/token/" + acct3_guid});
+    auto value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/severely/divided/token/" + acct3_guid});
     EXPECT_EQ(10, value->get<int64_t>());
     // convert from 'Asset-Bank#Bank' to 'Sav Bank' guid
     value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + acct4_guid});
@@ -366,14 +350,14 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
     EXPECT_EQ(5, value->get<int64_t>());
     // convert from 'Expense#Drink' to 'Drink' guid
     value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + sausage + "/" + acct2_guid});
-    EXPECT_EQ(2, value->get<int64_t>());
+    /*We put in 2, then called it once to bring it up to 3.*/
+    EXPECT_EQ(3, value->get<int64_t>());
     // convert from 'Expense#Food' to 'Food' guid but add to original value
     value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + acct1_guid});
     EXPECT_EQ(5, value->get<int64_t>());
-    // Check for run once flag
-    auto vals = book->get_slot({"changed-bayesian-to-guid"});
-    EXPECT_STREQ("true", vals->get<const char*>());
-    EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account)));
+    // Keep GUID value from original
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + acct1_guid});
+    EXPECT_EQ(10, value->get<int64_t>());
     EXPECT_TRUE(qof_instance_get_dirty_flag(QOF_INSTANCE(t_bank_account)));
 }
 

commit f782be1a5116a48b9e8521890da727561742520b
Author: lmat <dartme18 at gmail.com>
Date:   Wed Dec 6 13:52:01 2017 -0800

    Code review responses
    
    Using Aliases to represent cmplicated types
    Corrected variable-sized array on stack
    Using PascalCase for type names and aliases

diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 6f09ce9..67692b3 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -58,6 +58,10 @@ static const char *KEY_ASSOC_INCOME_ACCOUNT = "ofx/associated-income-account";
 #define AB_BANK_CODE "bank-code"
 #define AB_TRANS_RETRIEVAL "trans-retrieval"
 
+using FinalProbabilityVec=std::vector<std::pair<std::string, int32_t>>;
+using ProbabilityVec=std::vector<std::pair<std::string, struct AccountProbability>>;
+using FlatKvpEntry=std::pair<std::string, KvpValue*>;
+
 enum
 {
     LAST_SIGNAL
@@ -3027,6 +3031,7 @@ gnc_account_get_full_name(const Account *account)
     AccountPrivate *priv;
     const Account *a;
     char *fullname;
+    gchar **names;
     int level;
 
     /* So much for hardening the API. Too many callers to this function don't
@@ -3053,7 +3058,7 @@ gnc_account_get_full_name(const Account *account)
 
     /* Get all the pointers in the right order. The root node "entry"
      * becomes the terminating NULL pointer for the array of strings. */
-    gchar* names[level*sizeof(gchar*)];
+    names = (gchar **)g_malloc(level * sizeof(gchar *));
     names[--level] = NULL;
     for (a = account; level > 0; a = priv->parent)
     {
@@ -3063,6 +3068,7 @@ gnc_account_get_full_name(const Account *account)
 
     /* Build the full name */
     fullname =  g_strjoinv(account_separator, names);
+    g_free(names);
 
     return fullname;
 }
@@ -5151,13 +5157,13 @@ gnc_account_imap_delete_account (GncImportMatchMap *imap,
   where p(AB) = (a*b)/[a*b + (1-a)(1-b)], product is (a*b),
   product_difference is (1-a) * (1-b)
  */
-struct account_probability
+struct AccountProbability
 {
     double product; /* product of probabilities */
     double product_difference; /* product of (1-probabilities) */
 };
 
-struct account_token_count
+struct AccountTokenCount
 {
     std::string account_guid;
     int64_t token_count; /** occurrences of a given token for this account_guid */
@@ -5166,26 +5172,26 @@ struct account_token_count
 /** total_count and the token_count for a given account let us calculate the
  * probability of a given account with any single token
  */
-struct token_accounts_info
+struct TokenAccountsInfo
 {
-    std::vector<account_token_count> accounts;
+    std::vector<AccountTokenCount> accounts;
     int64_t total_count;
 };
 
 /** holds an account guid and its corresponding integer probability
   the integer probability is some factor of 10
  */
-struct account_info
+struct AccountInfo
 {
     std::string account_guid;
     int32_t probability;
 };
 
 static void
-build_token_info(char const * key, KvpValue * value, token_accounts_info & tokenInfo)
+build_token_info(char const * key, KvpValue * value, TokenAccountsInfo & tokenInfo)
 {
     tokenInfo.total_count += value->get<int64_t>();
-    account_token_count this_account;
+    AccountTokenCount this_account;
     std::string account_guid {key};
     /*By convention, the key ends with the account GUID.*/
     this_account.account_guid = account_guid.substr(account_guid.size() - GUID_ENCODING_LENGTH);
@@ -5198,10 +5204,10 @@ build_token_info(char const * key, KvpValue * value, token_accounts_info & token
   0.10 * 100000 = 10000 */
 static constexpr int probability_factor = 100000;
 
-static std::vector<std::pair<std::string, int32_t>>
-build_probabilities(std::vector<std::pair<std::string, account_probability>> const & first_pass)
+static FinalProbabilityVec
+build_probabilities(ProbabilityVec const & first_pass)
 {
-    std::vector<std::pair<std::string, int32_t>> ret;
+    FinalProbabilityVec ret;
     for (auto const & first_pass_prob : first_pass)
     {
         auto const & account_probability = first_pass_prob.second;
@@ -5216,31 +5222,31 @@ build_probabilities(std::vector<std::pair<std::string, account_probability>> con
     return ret;
 }
 
-static account_info
-highest_probability(std::vector<std::pair<std::string, int32_t>> const & probabilities)
+static AccountInfo
+highest_probability(FinalProbabilityVec const & probabilities)
 {
-    account_info ret {"", std::numeric_limits<int32_t>::min()};
+    AccountInfo ret {"", std::numeric_limits<int32_t>::min()};
     for (auto const & prob : probabilities)
         if (prob.second > ret.probability)
-            ret = account_info{prob.first, prob.second};
+            ret = AccountInfo {prob.first, prob.second};
     return ret;
 }
 
-static std::vector<std::pair<std::string, account_probability>>
+static ProbabilityVec
 get_first_pass_probabilities(GncImportMatchMap * imap, GList * tokens)
 {
-    std::vector<std::pair<std::string, account_probability>> ret;
+    ProbabilityVec ret;
     /* find the probability for each account that contains any of the tokens
      * in the input tokens list. */
     for (auto current_token = tokens; current_token; current_token = current_token->next)
     {
-        token_accounts_info tokenInfo{};
+        TokenAccountsInfo tokenInfo{};
         auto path = std::string{IMAP_FRAME_BAYES "/"} + static_cast <char const *> (current_token->data);
         qof_instance_foreach_slot_prefix (QOF_INSTANCE (imap->acc), path, &build_token_info, tokenInfo);
         for (auto const & current_account_token : tokenInfo.accounts)
         {
             auto item = std::find_if(ret.begin(), ret.end(), [&current_account_token]
-                (std::pair<std::string, account_probability> const & a) {
+                (std::pair<std::string, AccountProbability> const & a) {
                     return current_account_token.account_guid == a.first;
                 });
             if (item != ret.end())
@@ -5253,7 +5259,7 @@ get_first_pass_probabilities(GncImportMatchMap * imap, GList * tokens)
             else
             {
                 /* add a new entry */
-                account_probability new_probability;
+                AccountProbability new_probability;
                 new_probability.product = ((double)current_account_token.token_count /
                                       (double)tokenInfo.total_count);
                 new_probability.product_difference = 1 - (new_probability.product);
@@ -5385,16 +5391,11 @@ build_non_bayes (const char *key, const GValue *value, gpointer user_data)
 {
     if (!G_VALUE_HOLDS_BOXED (value))
         return;
-
     QofBook     *book;
     GncGUID     *guid = NULL;
     gchar       *kvp_path;
     gchar       *guid_string = NULL;
-
-    struct imap_info *imapInfo_node;
-
-    struct imap_info *imapInfo = (struct imap_info*)user_data;
-
+    auto imapInfo = (GncImapInfo*)user_data;
     // Get the book
     book = qof_instance_get_book (imapInfo->source_account);
 
@@ -5408,7 +5409,7 @@ build_non_bayes (const char *key, const GValue *value, gpointer user_data)
 
     PINFO("build_non_bayes: kvp_path is '%s'", kvp_path);
 
-    imapInfo_node = static_cast <imap_info*> (g_malloc(sizeof(*imapInfo_node)));
+    auto imapInfo_node = static_cast <GncImapInfo*> (g_malloc(sizeof(GncImapInfo)));
 
     imapInfo_node->source_account = imapInfo->source_account;
     imapInfo_node->map_account    = xaccAccountLookup (guid, book);
@@ -5435,7 +5436,7 @@ parse_bayes_imap_info (std::string const & imap_bayes_entry)
 }
 
 static void
-build_bayes (const char *key, KvpValue * value, imap_info & imapInfo)
+build_bayes (const char *key, KvpValue * value, GncImapInfo & imapInfo)
 {
     auto slots = qof_instance_get_slots_prefix (QOF_INSTANCE (imapInfo.source_account), IMAP_FRAME_BAYES);
     if (!slots.size()) return;
@@ -5446,7 +5447,7 @@ build_bayes (const char *key, KvpValue * value, imap_info & imapInfo)
         GncGUID guid = temp_guid;
         auto map_account = xaccAccountLookup (&guid, gnc_account_get_book (imapInfo.source_account));
         std::string category_head {std::get <0> (parsed_key) + "/" + std::get <1> (parsed_key)};
-        auto imap_node = static_cast <imap_info*> (g_malloc (sizeof (imap_info)));
+        auto imap_node = static_cast <GncImapInfo*> (g_malloc (sizeof (GncImapInfo)));
         auto count = entry.second->get <int64_t> ();
         imap_node->source_account = imapInfo.source_account;
         imap_node->map_account = map_account;
@@ -5534,29 +5535,23 @@ gnc_account_delete_map_entry (Account *acc, char *full_category, gboolean empty)
 
 /*******************************************************************************/
 
-static gchar *
-look_for_old_separator_descendants (Account *root, gchar const *full_name, const gchar *separator)
+static std::string
+look_for_old_separator_descendants (Account *root, std::string const & full_name, const gchar *separator)
 {
     GList *top_accounts, *ptr;
     gint   found_len = 0;
     gchar  found_sep;
-    gchar * new_name = nullptr;
-
     top_accounts = gnc_account_get_descendants (root);
-
-    PINFO("Incoming full_name is '%s', current separator is '%s'", full_name, separator);
-
+    PINFO("Incoming full_name is '%s', current separator is '%s'", full_name.c_str (), separator);
     /* Go through list of top level accounts */
     for (ptr = top_accounts; ptr; ptr = g_list_next (ptr))
     {
         const gchar *name = xaccAccountGetName (static_cast <Account const *> (ptr->data));
-
         // we are looking for the longest top level account that matches
-        if (g_str_has_prefix (full_name, name))
+        if (g_str_has_prefix (full_name.c_str (), name))
         {
             gint name_len = strlen (name);
             const gchar old_sep = full_name[name_len];
-
             if (!g_ascii_isalnum (old_sep)) // test for non alpha numeric
             {
                 if (name_len > found_len)
@@ -5568,13 +5563,10 @@ look_for_old_separator_descendants (Account *root, gchar const *full_name, const
         }
     }
     g_list_free (top_accounts); // Free the List
-    new_name = g_strdup (full_name);
-
+    std::string new_name {full_name};
     if (found_len > 1)
-        g_strdelimit (new_name, &found_sep, *separator);
-
+        std::replace (new_name.begin (), new_name.end (), found_sep, *separator);
     PINFO("Return full_name is '%s'", new_name);
-
     return new_name;
 }
 
@@ -5584,17 +5576,16 @@ get_guid_from_account_name (Account * root, std::string const & name)
     auto map_account = gnc_account_lookup_by_full_name (root, name.c_str ());
     if (!map_account)
     {
-        auto temp_account_name = look_for_old_separator_descendants (root, name.c_str (),
+        auto temp_account_name = look_for_old_separator_descendants (root, name,
              gnc_get_account_separator_string ());
-        map_account = gnc_account_lookup_by_full_name (root, temp_account_name);
-        g_free (temp_account_name);
+        map_account = gnc_account_lookup_by_full_name (root, temp_account_name.c_str ());
     }
     auto temp_guid = gnc::GUID {*xaccAccountGetGUID (map_account)};
     return temp_guid.to_string ();
 }
 
-static std::pair <std::string, KvpValue*>
-convert_entry (std::pair <std::vector <std::string>, KvpValue*> entry, Account* root)
+static FlatKvpEntry
+convert_entry (KvpEntry entry, Account* root)
 {
     /*We need to make a copy here.*/
     auto account_name = entry.first.back();
@@ -5607,7 +5598,7 @@ convert_entry (std::pair <std::vector <std::string>, KvpValue*> entry, Account*
     return {new_key, entry.second};
 }
 
-static std::vector<std::pair<std::string, KvpValue*>>
+static std::vector<FlatKvpEntry>
 get_new_guid_imap (Account * acc)
 {
     auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
@@ -5617,7 +5608,7 @@ get_new_guid_imap (Account * acc)
     auto imap_frame = slot->get<KvpFrame*> ();
     auto flat_kvp = imap_frame->flatten_kvp ();
     auto root = gnc_account_get_root (acc);
-    std::vector <std::pair <std::string, KvpValue*>> ret;
+    std::vector <FlatKvpEntry> ret;
     for (auto const & flat_entry : flat_kvp)
         ret.emplace_back (convert_entry (flat_entry, root));
     return ret;
@@ -5637,7 +5628,7 @@ convert_imap_account_bayes_to_guid (Account *acc)
         xaccAccountCommitEdit(acc);
         return false;
     }
-    std::for_each(new_imap.begin(), new_imap.end(), [&frame] (std::pair<std::string, KvpValue*> const & entry) {
+    std::for_each(new_imap.begin(), new_imap.end(), [&frame] (FlatKvpEntry const & entry) {
         frame->set({entry.first.c_str()}, entry.second);
     });
     qof_instance_set_dirty (QOF_INSTANCE (acc));
diff --git a/libgnucash/engine/kvp-frame.cpp b/libgnucash/engine/kvp-frame.cpp
index 9687cc1..6f0fc4a 100644
--- a/libgnucash/engine/kvp-frame.cpp
+++ b/libgnucash/engine/kvp-frame.cpp
@@ -423,7 +423,7 @@ gnc_value_list_get_type (void)
 }
 
 void
-KvpFrame::flatten_kvp_impl(std::vector <std::string> path, std::vector <std::pair <std::vector <std::string>, KvpValue*>> & entries) const noexcept
+KvpFrame::flatten_kvp_impl(std::vector <std::string> path, std::vector <KvpEntry> & entries) const noexcept
 {
     for (auto const & entry : m_valuemap)
     {
@@ -443,10 +443,10 @@ KvpFrame::flatten_kvp_impl(std::vector <std::string> path, std::vector <std::pai
     }
 }
 
-std::vector <std::pair <std::vector <std::string>, KvpValue*>>
+std::vector <KvpEntry>
 KvpFrame::flatten_kvp(void) const noexcept
 {
-    std::vector <std::pair <std::vector <std::string>, KvpValue*>> ret;
+    std::vector <KvpEntry> ret;
     flatten_kvp_impl({}, ret);
     return ret;
 }
diff --git a/libgnucash/engine/kvp-frame.hpp b/libgnucash/engine/kvp-frame.hpp
index 4cdf52d..23eb0c6 100644
--- a/libgnucash/engine/kvp-frame.hpp
+++ b/libgnucash/engine/kvp-frame.hpp
@@ -92,6 +92,7 @@
 #include <algorithm>
 #include <iostream>
 using Path = std::vector<std::string>;
+using KvpEntry = std::pair <std::vector <std::string>, KvpValue*>;
 
 /** Implements KvpFrame.
  *  It's a struct because QofInstance needs to use the typename to declare a
@@ -216,7 +217,7 @@ struct KvpFrameImpl
      * Returns all keys and values of this frame recursively, flattening
      * the frame-containing values.
      */
-    std::vector <std::pair <std::vector <std::string>, KvpValue*>>
+    std::vector <KvpEntry>
     flatten_kvp(void) const noexcept;
 
     /** Test for emptiness
@@ -230,7 +231,7 @@ struct KvpFrameImpl
 
     KvpFrame * get_child_frame_or_nullptr (Path const &) noexcept;
     KvpFrame * get_child_frame_or_create (Path const &) noexcept;
-    void flatten_kvp_impl(std::vector <std::string>, std::vector <std::pair <std::vector <std::string>, KvpValue*>> &) const noexcept;
+    void flatten_kvp_impl(std::vector <std::string>, std::vector <KvpEntry> &) const noexcept;
     KvpValue * set_impl (std::string const &, KvpValue *) noexcept;
 };
 

commit 3312fe2dcdc6a97e5c604b9149bd2026241ac7ff
Author: lmat <dartme18 at gmail.com>
Date:   Fri Dec 1 13:40:06 2017 -0500

    Changed some constants to constexpr

diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 19d829d..6f09ce9 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -5193,10 +5193,10 @@ build_token_info(char const * key, KvpValue * value, token_accounts_info & token
     tokenInfo.accounts.push_back(this_account);
 }
 
-/** We scale the probability values by PROBABILITY_FACTOR.
-  ie. with PROBABILITY_FACTOR of 100000, 10% would be
+/** We scale the probability values by probability_factor.
+  ie. with probability_factor of 100000, 10% would be
   0.10 * 100000 = 10000 */
-#define PROBABILITY_FACTOR 100000
+static constexpr int probability_factor = 100000;
 
 static std::vector<std::pair<std::string, int32_t>>
 build_probabilities(std::vector<std::pair<std::string, account_probability>> const & first_pass)
@@ -5210,7 +5210,7 @@ build_probabilities(std::vector<std::pair<std::string, account_probability>> con
          * and product difference ((1-A)(1-B)...)
          */
         int32_t probability = (account_probability.product /
-                (account_probability.product + account_probability.product_difference)) * PROBABILITY_FACTOR;
+                (account_probability.product + account_probability.product_difference)) * probability_factor;
         ret.push_back({first_pass_prob.first, probability});
     }
     return ret;
@@ -5264,7 +5264,7 @@ get_first_pass_probabilities(GncImportMatchMap * imap, GList * tokens)
     return ret;
 }
 
-#define threshold (.90 * PROBABILITY_FACTOR) /* 90% */
+static constexpr double threshold = .90 * probability_factor; /* 90% */
 
 /** Look up an Account in the map */
 Account*

commit 29ad8ff9b07165d88d5fa722e233618c9610fe47
Author: lmat <dartme18 at gmail.com>
Date:   Tue Nov 28 17:15:07 2017 -0500

    Remove unused kvp function

diff --git a/libgnucash/engine/kvp-frame.hpp b/libgnucash/engine/kvp-frame.hpp
index 32dd102..4cdf52d 100644
--- a/libgnucash/engine/kvp-frame.hpp
+++ b/libgnucash/engine/kvp-frame.hpp
@@ -192,12 +192,6 @@ struct KvpFrameImpl
      */
     KvpValue* get_slot(Path keys) noexcept;
 
-    /**
-     * proc is called with each of the immediate contents of this frame, passing it the key,
-     * value, and specified data.
-     */
-    void for_each_slot(void (*proc)(const char *key, KvpValue *, void *data), void* data) const noexcept;
-
     /** The function should be of the form:
      * <anything> func (char const *, KvpValue *, data_type &);
      * Do not pass nullptr as the function.
diff --git a/libgnucash/engine/qofinstance-p.h b/libgnucash/engine/qofinstance-p.h
index 9967030..c0d79f9 100644
--- a/libgnucash/engine/qofinstance-p.h
+++ b/libgnucash/engine/qofinstance-p.h
@@ -175,18 +175,6 @@ void qof_instance_slot_path_delete_if_empty (QofInstance const *, std::vector<st
 std::vector <std::pair <std::string, KvpValue*>>
 qof_instance_get_slots_prefix (QofInstance const *, std::string const & prefix);
 
-/* Don't pass nullptr as the function */
-template<typename func_type, typename data_type>
-void qof_instance_foreach_slot_temp (QofInstance const * inst, std::string const & path,
-        func_type const & func, data_type & data)
-{
-    auto slot = inst->kvp_data->get_slot({path});
-    if (slot == nullptr || slot->get_type() != KvpValue::Type::FRAME)
-        return;
-    auto frame = slot->get<KvpFrame*>();
-    frame->for_each_slot(func, data);
-}
-
 /**
  * Similar to qof_instance_foreach_slot, but we don't traverse the depth of the key value frame,
  * we only check the root level for keys that match the specified prefix.

commit 4a88f05d1159350812969d952bf3d3d9a5173c9a
Author: lmat <dartme18 at gmail.com>
Date:   Tue Nov 28 15:44:20 2017 -0500

    kvp string: allocate enough space
    
    We need to allocate enough space for the terminating null character.
    Also, I double-checked the documents for std::basic_string::c_str () and
    verified that it does guarantee the terminating null, so I put a comment
    in the code that depends on that.

diff --git a/libgnucash/engine/gnc-budget.c b/libgnucash/engine/gnc-budget.c
index 16c121e..4da6cf1 100644
--- a/libgnucash/engine/gnc-budget.c
+++ b/libgnucash/engine/gnc-budget.c
@@ -489,7 +489,7 @@ void
 gnc_budget_unset_account_period_value(GncBudget *budget, const Account *account,
                                       guint period_num)
 {
-    gchar path_part_one [GUID_ENCODING_LENGTH];
+    gchar path_part_one [GUID_ENCODING_LENGTH + 1];
     gchar path_part_two [GNC_BUDGET_MAX_NUM_PERIODS_DIGITS];
 
     g_return_if_fail (budget != NULL);
@@ -511,7 +511,7 @@ void
 gnc_budget_set_account_period_value(GncBudget *budget, const Account *account,
                                     guint period_num, gnc_numeric val)
 {
-    gchar path_part_one [GUID_ENCODING_LENGTH];
+    gchar path_part_one [GUID_ENCODING_LENGTH + 1];
     gchar path_part_two [GNC_BUDGET_MAX_NUM_PERIODS_DIGITS];
 
     /* Watch out for an off-by-one error here:
@@ -553,7 +553,7 @@ gnc_budget_is_account_period_value_set(const GncBudget *budget,
                                        guint period_num)
 {
     GValue v = G_VALUE_INIT;
-    gchar path_part_one [GUID_ENCODING_LENGTH];
+    gchar path_part_one [GUID_ENCODING_LENGTH + 1];
     gchar path_part_two [GNC_BUDGET_MAX_NUM_PERIODS_DIGITS];
     gconstpointer ptr = NULL;
 
@@ -573,7 +573,7 @@ gnc_budget_get_account_period_value(const GncBudget *budget,
                                     guint period_num)
 {
     gnc_numeric *numeric = NULL;
-    gchar path_part_one [GUID_ENCODING_LENGTH];
+    gchar path_part_one [GUID_ENCODING_LENGTH + 1];
     gchar path_part_two [GNC_BUDGET_MAX_NUM_PERIODS_DIGITS];
     GValue v = G_VALUE_INIT;
 
diff --git a/libgnucash/engine/guid.cpp b/libgnucash/engine/guid.cpp
index 5706802..11aaebf 100644
--- a/libgnucash/engine/guid.cpp
+++ b/libgnucash/engine/guid.cpp
@@ -177,7 +177,9 @@ guid_to_string_buff (const GncGUID * guid, gchar *str)
 
     gnc::GUID temp {*guid};
     auto val = temp.to_string ();
-    /*We need to be sure to copy the terminating null character.*/
+    /*We need to be sure to copy the terminating null character.
+     * The standard guarantees that std::basic_string::c_str ()
+     * returns with a terminating null character, too.*/
     std::copy (val.c_str (), val.c_str () + val.size () + 1, str);
     return str + val.size ();
 }

commit 5b03182963de1cc5c7e7a3d7cc6fd29ce6339848
Author: lmat <dartme18 at gmail.com>
Date:   Tue Nov 28 15:43:24 2017 -0500

    Correct kvp to_string typo

diff --git a/libgnucash/engine/kvp-value.cpp b/libgnucash/engine/kvp-value.cpp
index a0329d2..990197e 100644
--- a/libgnucash/engine/kvp-value.cpp
+++ b/libgnucash/engine/kvp-value.cpp
@@ -174,7 +174,7 @@ struct to_string_visitor : boost::static_visitor<void>
         {
             output << "(null)";
         }
-        output << " (timespec)";
+        output << " (gnc_numeric)";
     }
 
     void operator()(GncGUID * val)

commit f260a01bfd523886c807b3c901b0700712f577cd
Author: lmat <dartme18 at gmail.com>
Date:   Thu Nov 16 12:57:31 2017 -0500

    Keep tokens as they are, don't translate them
    
    Before, it was necessary to remove '/' from tokens so that they won't be
    divided up within kvp. Now that kvp doesn't parse tokens, it's okay to
    pass '/', and it's better not to translate user-provided tokens if at all
    possible.

diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 895ff8f..19d829d 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -5234,10 +5234,8 @@ get_first_pass_probabilities(GncImportMatchMap * imap, GList * tokens)
      * in the input tokens list. */
     for (auto current_token = tokens; current_token; current_token = current_token->next)
     {
-        auto translated_token = std::string {static_cast <char const *> (current_token->data)};
-        std::replace (translated_token.begin (), translated_token.end (), '/', '-');
         token_accounts_info tokenInfo{};
-        auto path = std::string{IMAP_FRAME_BAYES "-"} + translated_token;
+        auto path = std::string{IMAP_FRAME_BAYES "/"} + static_cast <char const *> (current_token->data);
         qof_instance_foreach_slot_prefix (QOF_INSTANCE (imap->acc), path, &build_token_info, tokenInfo);
         for (auto const & current_account_token : tokenInfo.accounts)
         {
@@ -5329,7 +5327,6 @@ change_imap_entry (GncImportMatchMap *imap, std::string const & path, int64_t to
     gnc_features_set_used (imap->book, GNC_FEATURE_GUID_BAYESIAN);
 }
 
-
 /** Updates the imap for a given account using a list of tokens */
 void
 gnc_account_imap_add_account_bayes (GncImportMatchMap *imap,
@@ -5369,9 +5366,7 @@ gnc_account_imap_add_account_bayes (GncImportMatchMap *imap,
         /* start off with one token for this account */
         token_count = 1;
         PINFO("adding token '%s'", (char*)current_token->data);
-        std::string translated_token {static_cast<char*>(current_token->data)};
-        std::replace(translated_token.begin(), translated_token.end(), '/', '-');
-        auto path = std::string {IMAP_FRAME_BAYES} + '-' + translated_token + '-' + guid_string;
+        auto path = std::string {IMAP_FRAME_BAYES} + '/' + static_cast<char*>(current_token->data) + '/' + guid_string;
         /* change the imap entry for the account */
         change_imap_entry (imap, path, token_count);
     }
@@ -5450,7 +5445,7 @@ build_bayes (const char *key, KvpValue * value, imap_info & imapInfo)
         auto temp_guid = gnc::GUID::from_string (std::get <2> (parsed_key));
         GncGUID guid = temp_guid;
         auto map_account = xaccAccountLookup (&guid, gnc_account_get_book (imapInfo.source_account));
-        std::string category_head {std::get <0> (parsed_key) + "-" + std::get <1> (parsed_key)};
+        std::string category_head {std::get <0> (parsed_key) + "/" + std::get <1> (parsed_key)};
         auto imap_node = static_cast <imap_info*> (g_malloc (sizeof (imap_info)));
         auto count = entry.second->get <int64_t> ();
         imap_node->source_account = imapInfo.source_account;
@@ -5609,7 +5604,6 @@ convert_entry (std::pair <std::vector <std::string>, KvpValue*> entry, Account*
     entry.first.emplace_back (guid_str);
     std::string new_key {std::accumulate (entry.first.begin(), entry.first.end(), std::string {})};
     new_key = IMAP_FRAME_BAYES + new_key;
-    std::replace (new_key.begin(), new_key.end(), '/', '-');
     return {new_key, entry.second};
 }
 
diff --git a/libgnucash/engine/test/gtest-import-map.cpp b/libgnucash/engine/test/gtest-import-map.cpp
index d811574..df72445 100644
--- a/libgnucash/engine/test/gtest-import-map.cpp
+++ b/libgnucash/engine/test/gtest-import-map.cpp
@@ -254,12 +254,12 @@ TEST_F(ImapBayesTest, FindAccountBayes)
     auto acct2_guid = guid_to_string (xaccAccountGetGUID(t_expense_account2));
     auto value = new KvpValue(INT64_C(42));
 
-    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid}, value);
-    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid}, new KvpValue{*value});
-    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid}, new KvpValue{*value});
-    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid}, new KvpValue{*value});
-    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct1_guid}, new KvpValue{*value});
-    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct2_guid}, new KvpValue{*value});
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + acct1_guid}, value);
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "/" + bar + "/" + acct1_guid}, new KvpValue{*value});
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "/" + baz + "/" + acct2_guid}, new KvpValue{*value});
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "/" + waldo + "/" + acct2_guid}, new KvpValue{*value});
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "/" + pepper + "/" + acct1_guid}, new KvpValue{*value});
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + acct2_guid}, new KvpValue{*value});
 
     auto account = gnc_account_imap_find_account_bayes(t_imap, t_list1);
     EXPECT_EQ(t_expense_account1, account);
@@ -292,29 +292,29 @@ TEST_F(ImapBayesTest, AddAccountBayes)
     auto root = qof_instance_get_slots(QOF_INSTANCE(t_bank_account));
     auto acct1_guid = guid_to_string (xaccAccountGetGUID(t_expense_account1));
     auto acct2_guid = guid_to_string (xaccAccountGetGUID(t_expense_account2));
-    auto value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-foo-bar"});
+    auto value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/foo/bar"});
     auto check_account = [this](KvpValue* v) {
         return (v->get<const char*>(), this->t_imap->book); };
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + acct1_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + bar + "/" + acct1_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + baz + "/" + acct2_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + waldo + "/" + acct2_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct1_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + pepper + "/" + acct1_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct2_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + acct2_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct1_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + baz + "/" + acct1_guid});
     EXPECT_EQ(nullptr, value);
 
     qof_instance_increase_editlevel(QOF_INSTANCE(t_bank_account));
     gnc_account_imap_add_account_bayes(t_imap, t_list2, t_expense_account2);
     qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
     qof_instance_reset_editlevel(QOF_INSTANCE(t_bank_account));
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + baz + "/" + acct2_guid});
     EXPECT_EQ(2, value->get<int64_t>());
 }
 
@@ -335,16 +335,16 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
     auto val2 = new KvpValue(static_cast<int64_t>(5));
     auto val3 = new KvpValue(static_cast<int64_t>(2));
     // Test for existing entries, all will be 1
-    auto value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid});
+    auto value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + acct1_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + bar + "/" + acct1_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + baz + "/" + acct2_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + waldo + "/" + acct2_guid});
     EXPECT_EQ(1, value->get<int64_t>());
     // Set up some old entries
-    root->set_path({IMAP_FRAME_BAYES, "token", "with", "slashes", "Asset-Bank"}, val1);
+    root->set_path({IMAP_FRAME_BAYES, "severely", "divided", "token", "Asset-Bank"}, val1);
     root->set_path({IMAP_FRAME_BAYES, salt, "Asset-Bank#Bank"}, new KvpValue{*val1});
     root->set_path({IMAP_FRAME_BAYES, salt, "Asset>Bank#Bank"}, val2);
     root->set_path({IMAP_FRAME_BAYES, pork, "Expense#Food"}, new KvpValue{*val2});
@@ -356,19 +356,19 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
     // Start Convert
     gnc_account_imap_convert_bayes (t_imap->book);
     // convert from 'Asset-Bank' to 'Asset-Bank' guid
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-token-with-slashes-" + acct3_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/severely/divided/token/" + acct3_guid});
     EXPECT_EQ(10, value->get<int64_t>());
     // convert from 'Asset-Bank#Bank' to 'Sav Bank' guid
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct4_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + acct4_guid});
     EXPECT_EQ(10, value->get<int64_t>());
     // convert from 'Expense#Food' to 'Food' guid
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + pork + "-" + acct1_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + pork + "/" + acct1_guid});
     EXPECT_EQ(5, value->get<int64_t>());
     // convert from 'Expense#Drink' to 'Drink' guid
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + sausage + "-" + acct2_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + sausage + "/" + acct2_guid});
     EXPECT_EQ(2, value->get<int64_t>());
     // convert from 'Expense#Food' to 'Food' guid but add to original value
-    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid});
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + acct1_guid});
     EXPECT_EQ(5, value->get<int64_t>());
     // Check for run once flag
     auto vals = book->get_slot({"changed-bayesian-to-guid"});
@@ -402,9 +402,9 @@ TEST_F (ImapBayesTest, get_bayes_info)
     EXPECT_EQ (info->source_account, t_bank_account);
     EXPECT_EQ (info->map_account, t_expense_account1);
     auto acct1_guid = guid_to_string (xaccAccountGetGUID(t_expense_account1)); //Food
-    EXPECT_STREQ (info->full_category, (std::string {IMAP_FRAME_BAYES} + "-one-two-three-" + acct1_guid).c_str ());
-    EXPECT_STREQ (info->match_string, "one-two-three");
-    EXPECT_STREQ (info->category_head, (std::string {IMAP_FRAME_BAYES} + "-one-two-three").c_str ());
+    EXPECT_STREQ (info->full_category, (std::string {IMAP_FRAME_BAYES} + "/one/two/three/" + acct1_guid).c_str ());
+    EXPECT_STREQ (info->match_string, "one/two/three");
+    EXPECT_STREQ (info->category_head, (std::string {IMAP_FRAME_BAYES} + "/one/two/three").c_str ());
     EXPECT_STREQ (info->count, "1");
 }
 

commit 551549598a45aff0accef9125b8100f7cf0f1330
Author: lmat <dartme18 at gmail.com>
Date:   Wed Nov 15 15:24:45 2017 -0500

    Corrected memory management issue

diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 3ee7882..895ff8f 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -5326,10 +5326,6 @@ change_imap_entry (GncImportMatchMap *imap, std::string const & path, int64_t to
 
     // Add or Update the entry based on guid
     qof_instance_set_path_kvp (QOF_INSTANCE (imap->acc), &value, {path});
-
-    /* Set a feature flag in the book for the change to use guid.
-     * This will prevent older GnuCash versions that don't support this feature
-     * from opening this file. */
     gnc_features_set_used (imap->book, GNC_FEATURE_GUID_BAYESIAN);
 }
 
@@ -5605,7 +5601,8 @@ get_guid_from_account_name (Account * root, std::string const & name)
 static std::pair <std::string, KvpValue*>
 convert_entry (std::pair <std::vector <std::string>, KvpValue*> entry, Account* root)
 {
-    auto const & account_name = entry.first.back();
+    /*We need to make a copy here.*/
+    auto account_name = entry.first.back();
     entry.first.pop_back();
     auto guid_str = get_guid_from_account_name (root, account_name);
     entry.first.emplace_back ("/");
@@ -5632,20 +5629,26 @@ get_new_guid_imap (Account * acc)
     return ret;
 }
 
-static void
+static bool
 convert_imap_account_bayes_to_guid (Account *acc)
 {
     auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
     if (!frame->get_keys().size())
-        return;
+        return false;
     auto new_imap = get_new_guid_imap(acc);
     xaccAccountBeginEdit(acc);
     frame->set({IMAP_FRAME_BAYES}, nullptr);
+    if (!new_imap.size ())
+    {
+        xaccAccountCommitEdit(acc);
+        return false;
+    }
     std::for_each(new_imap.begin(), new_imap.end(), [&frame] (std::pair<std::string, KvpValue*> const & entry) {
         frame->set({entry.first.c_str()}, entry.second);
     });
     qof_instance_set_dirty (QOF_INSTANCE (acc));
     xaccAccountCommitEdit(acc);
+    return true;
 }
 
 char const * run_once_key_to_guid {"changed-bayesian-to-guid"};
@@ -5658,7 +5661,8 @@ imap_convert_bayes_to_guid (QofBook * book)
     for (auto ptr = accts; ptr; ptr = g_list_next (ptr))
     {
         Account *acc = static_cast <Account*> (ptr->data);
-        convert_imap_account_bayes_to_guid (acc);
+        if (convert_imap_account_bayes_to_guid (acc))
+            gnc_features_set_used (book, GNC_FEATURE_GUID_BAYESIAN);
     }
     g_list_free (accts);
 }

commit d9eebd332b52b774f3ad5b4f0c85ce7ba0419381
Author: lmat <dartme18 at gmail.com>
Date:   Thu Nov 9 16:33:58 2017 -0500

    Renaming functions to get rid of temporary name
    
    _var_ was used to make sure I caught all references, but isn't intended
    as a permanent name.

diff --git a/libgnucash/engine/Scrub.c b/libgnucash/engine/Scrub.c
index a036fff..b4b744b 100644
--- a/libgnucash/engine/Scrub.c
+++ b/libgnucash/engine/Scrub.c
@@ -50,7 +50,7 @@
 #include "Transaction.h"
 #include "TransactionP.h"
 #include "gnc-commodity.h"
-#include <qofinstance-p.h>
+#include "qofinstance-p.h"
 
 #undef G_LOG_DOMAIN
 #define G_LOG_DOMAIN "gnc.engine.scrub"
@@ -1342,7 +1342,7 @@ xaccAccountScrubKvp (Account *account)
     {
         str2 = g_strstrip(g_value_dup_string(&v));
         if (strlen(str2) == 0)
-            qof_instance_slot_var_delete (QOF_INSTANCE (account), 1, "notes");
+            qof_instance_slot_delete (QOF_INSTANCE (account), "notes");
         g_free(str2);
     }
 
@@ -1350,9 +1350,9 @@ xaccAccountScrubKvp (Account *account)
     if ((G_VALUE_HOLDS_STRING (&v) &&
         strcmp(g_value_get_string (&v), "false") == 0) ||
         (G_VALUE_HOLDS_BOOLEAN (&v) && ! g_value_get_boolean (&v)))
-        qof_instance_slot_var_delete (QOF_INSTANCE (account), 1, "placeholder");
+        qof_instance_slot_delete (QOF_INSTANCE (account), "placeholder");
 
-    qof_instance_slot_var_delete_if_empty (QOF_INSTANCE (account), 1, "hbci");
+    qof_instance_slot_delete_if_empty (QOF_INSTANCE (account), "hbci");
 }
 
 /* ================================================================ */
diff --git a/libgnucash/engine/qofinstance-p.h b/libgnucash/engine/qofinstance-p.h
index 9fd5e4f..9967030 100644
--- a/libgnucash/engine/qofinstance-p.h
+++ b/libgnucash/engine/qofinstance-p.h
@@ -153,8 +153,8 @@ gboolean qof_instance_kvp_has_guid (const QofInstance *inst, const char *path,
 void qof_instance_kvp_merge_guids (const QofInstance *target,
                                    const QofInstance *donor, const char* path);
 gboolean qof_instance_has_slot (const QofInstance *inst, const char *path);
-void qof_instance_slot_var_delete (const QofInstance *, unsigned count, ...);
-void qof_instance_slot_var_delete_if_empty (const QofInstance *, unsigned count, ...);
+void qof_instance_slot_delete (const QofInstance *, const char * path);
+void qof_instance_slot_delete_if_empty (const QofInstance *, const char * path);
 void qof_instance_foreach_slot (const QofInstance *inst, const char *path,
                                 void(*proc)(const char*, const GValue*, void*),
                                 void* data);
diff --git a/libgnucash/engine/qofinstance.cpp b/libgnucash/engine/qofinstance.cpp
index 7a3b6bf..57cc6bd 100644
--- a/libgnucash/engine/qofinstance.cpp
+++ b/libgnucash/engine/qofinstance.cpp
@@ -1295,15 +1295,9 @@ void qof_instance_slot_path_delete (QofInstance const * inst, std::vector<std::s
 }
 
 void
-qof_instance_slot_var_delete (QofInstance const *inst, unsigned count, ...)
+qof_instance_slot_delete (QofInstance const *inst, char const * path)
 {
-    std::vector<std::string> path;
-    va_list args;
-    va_start (args, count);
-    for (unsigned i{0}; i < count; ++i)
-        path.push_back (va_arg (args, char const *));
-    va_end (args);
-    delete inst->kvp_data->set (path, nullptr);
+    delete inst->kvp_data->set ({path}, nullptr);
 }
 
 void qof_instance_slot_path_delete_if_empty (QofInstance const * inst, std::vector<std::string> const & path)
@@ -1318,20 +1312,14 @@ void qof_instance_slot_path_delete_if_empty (QofInstance const * inst, std::vect
 }
 
 void
-qof_instance_slot_var_delete_if_empty (QofInstance const *inst, unsigned count, ...)
+qof_instance_slot_delete_if_empty (QofInstance const *inst, char const * path)
 {
-    std::vector<std::string> path;
-    va_list args;
-    va_start (args, count);
-    for (unsigned i{0}; i < count; ++i)
-        path.push_back (va_arg (args, char const *));
-    va_end (args);
-    auto slot = inst->kvp_data->get_slot (path);
+    auto slot = inst->kvp_data->get_slot ({path});
     if (slot)
     {
         auto frame = slot->get <KvpFrame*> ();
         if (frame && frame->empty ())
-            delete inst->kvp_data->set (path, nullptr);
+            delete inst->kvp_data->set ({path}, nullptr);
     }
 }
 

commit 5636afc4a298c355a5ffb6f849a21977aba3ac9a
Author: lmat <dartme18 at gmail.com>
Date:   Mon Nov 6 14:51:25 2017 -0500

    Kvp no longer parses entries looking for delimiters

diff --git a/libgnucash/app-utils/test/test-option-util.cpp b/libgnucash/app-utils/test/test-option-util.cpp
index fd560fe..4c7d358 100644
--- a/libgnucash/app-utils/test/test-option-util.cpp
+++ b/libgnucash/app-utils/test/test-option-util.cpp
@@ -69,7 +69,7 @@ setup_kvp (Fixture *fixture, gconstpointer pData)
                      "autoreadonly-days", (double)21,
                      NULL);
 
-    slots->set_path("options/Business/Company Name",
+    slots->set_path({"options", "Business", "Company Name"},
                new KvpValue("Bogus Company"));
     qof_commit_edit (QOF_INSTANCE (book));
 }
@@ -120,10 +120,10 @@ test_option_save (Fixture *fixture, gconstpointer pData)
 					       OPTION_NAME_AUTO_READONLY_DAYS,
 					       17));
     qof_book_save_options (book, gnc_option_db_save, odb, TRUE);
-    g_assert_cmpstr (slots->get_slot("options/Accounts/Use Trading Accounts")->get<const char*>(), == , "t");
-    g_assert_cmpstr (slots->get_slot("options/Accounts/Use Split Action Field for Number")->get<const char*>(), == , "t");
-    g_assert_cmpstr (slots->get_slot("options/Business/Company Name")->get<const char*>(), ==, "Bogus Company");
-    g_assert_cmpfloat (slots->get_slot("options/Accounts/Day Threshold for Read-Only Transactions (red line)")->get<double>(), ==, 17);
+    g_assert_cmpstr (slots->get_slot({"options", "Accounts", "Use Trading Accounts"})->get<const char*>(), == , "t");
+    g_assert_cmpstr (slots->get_slot({"options", "Accounts", "Use Split Action Field for Number"})->get<const char*>(), == , "t");
+    g_assert_cmpstr (slots->get_slot({"options", "Business", "Company Name"})->get<const char*>(), ==, "Bogus Company");
+    g_assert_cmpfloat (slots->get_slot({"options", "Accounts", "Day Threshold for Read-Only Transactions (red line)"})->get<double>(), ==, 17);
 
     gnc_option_db_destroy (odb);
 }
diff --git a/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp b/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp
index 245ca95..8c0d75e 100644
--- a/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp
+++ b/libgnucash/backend/dbi/test/test-backend-dbi-basic.cpp
@@ -132,15 +132,13 @@ setup_memory (Fixture* fixture, gconstpointer pData)
     xaccAccountSetCommodity (acct1, currency);
 
     auto frame = qof_instance_get_slots (QOF_INSTANCE (acct1));
-    frame->set ("int64-val", new KvpValue (INT64_C (100)));
-    frame->set ("double-val", new KvpValue (3.14159));
-    frame->set ("numeric-val", new KvpValue (gnc_numeric_zero ()));
-
-    frame->set ("timespec-val", new KvpValue (timespec_now ()));
-
-    frame->set ("string-val", new KvpValue ("abcdefghijklmnop"));
+    frame->set ({"int64-val"}, new KvpValue (INT64_C (100)));
+    frame->set ({"double-val"}, new KvpValue (3.14159));
+    frame->set ({"numeric-val"}, new KvpValue (gnc_numeric_zero ()));
+    frame->set ({"timespec-val"}, new KvpValue (timespec_now ()));
+    frame->set ({"string-val"}, new KvpValue ("abcdefghijklmnop"));
     auto guid = qof_instance_get_guid (QOF_INSTANCE (acct1));
-    frame->set ("guid-val", new KvpValue (const_cast<GncGUID*> (guid_copy (
+    frame->set ({"guid-val"}, new KvpValue (const_cast<GncGUID*> (guid_copy (
             guid))));
 
     gnc_account_append_child (root, acct1);
diff --git a/libgnucash/backend/sql/gnc-slots-sql.cpp b/libgnucash/backend/sql/gnc-slots-sql.cpp
index 30563a5..c8b36ff 100644
--- a/libgnucash/backend/sql/gnc-slots-sql.cpp
+++ b/libgnucash/backend/sql/gnc-slots-sql.cpp
@@ -226,7 +226,7 @@ set_slot_from_value (slot_info_t* pInfo, KvpValue* pValue)
     case FRAME:
     {
         auto key = get_key_from_path (pInfo->path);
-        pInfo->pKvpFrame->set (key.c_str(), pValue);
+        pInfo->pKvpFrame->set ({key.c_str()}, pValue);
         break;
     }
     case LIST:
@@ -245,7 +245,7 @@ set_slot_from_value (slot_info_t* pInfo, KvpValue* pValue)
             frame->set_path ({path.c_str(), key.c_str()}, pValue);
         }
         else
-            frame->set (key.c_str(), pValue);
+            frame->set ({key.c_str()}, pValue);
         break;
     }
     }
@@ -464,7 +464,7 @@ set_guid_val (gpointer pObject,  gpointer pValue)
 
         slots_load_info (newInfo);
         pValue = new KvpValue {newInfo->pList};
-        pInfo->pKvpFrame->set (key.c_str(), pValue);
+        pInfo->pKvpFrame->set ({key.c_str()}, pValue);
 	delete newInfo;
         break;
     }
@@ -487,7 +487,7 @@ set_guid_val (gpointer pObject,  gpointer pValue)
         default:
         {
             auto key = get_key_from_path (pInfo->path);
-            pInfo->pKvpFrame->set (key.c_str(), new KvpValue {newFrame});
+            pInfo->pKvpFrame->set ({key.c_str()}, new KvpValue {newFrame});
             break;
         }
         }
diff --git a/libgnucash/backend/xml/io-gncxml-v1.cpp b/libgnucash/backend/xml/io-gncxml-v1.cpp
index df50648..53d6039 100644
--- a/libgnucash/backend/xml/io-gncxml-v1.cpp
+++ b/libgnucash/backend/xml/io-gncxml-v1.cpp
@@ -808,7 +808,7 @@ kvp_frame_slot_end_handler (gpointer data_for_children,
     if (key_node_count != 1) return (FALSE);
 
     value_cr->should_cleanup = TRUE;
-    f->set (key, value);
+    f->set ({key}, value);
     if (delete_value)
         delete value;
     return (TRUE);
diff --git a/libgnucash/backend/xml/sixtp-dom-parsers.cpp b/libgnucash/backend/xml/sixtp-dom-parsers.cpp
index af4b197..fa0dca1 100644
--- a/libgnucash/backend/xml/sixtp-dom-parsers.cpp
+++ b/libgnucash/backend/xml/sixtp-dom-parsers.cpp
@@ -440,7 +440,7 @@ dom_tree_to_kvp_frame_given (xmlNodePtr node, KvpFrame* frame)
                 if (val)
                 {
                     //We're deleting the old KvpValue returned by replace_nc().
-                    delete frame->set (key, val);
+                    delete frame->set ({key}, val);
                 }
                 else
                 {
diff --git a/libgnucash/backend/xml/test/test-kvp-frames.cpp b/libgnucash/backend/xml/test/test-kvp-frames.cpp
index b9736ce..508d600 100644
--- a/libgnucash/backend/xml/test/test-kvp-frames.cpp
+++ b/libgnucash/backend/xml/test/test-kvp-frames.cpp
@@ -25,7 +25,7 @@ test_kvp_get_slot (int run,
                    KvpFrame* test_frame1, const KvpValue* test_val1,
                    const gchar* test_key)
 {
-    auto test_val2 = test_frame1->get_slot (test_key);
+    auto test_val2 = test_frame1->get_slot ({test_key});
     auto msg = "KvpFrame::get_slot";
     if (compare (test_val1, test_val2) == 0)
     {
@@ -70,7 +70,7 @@ test_kvp_copy_get_slot (int run,
                         const gchar* test_key)
 {
     auto test_frame2 = new KvpFrame (*test_frame1);
-    auto test_val2 = test_frame2->get_slot (test_key);
+    auto test_val2 = test_frame2->get_slot ({test_key});
     auto msg = "KvpFrame::get_slot() from a copy-constructed frame";
     if (compare (test_val1, test_val2) == 0)
     {
@@ -114,7 +114,7 @@ test_kvp_frames1 (void)
         auto test_frame1 = new KvpFrame;
         auto test_key = get_random_string_without ("/");
 
-        test_frame1->set (test_key, test_val1);
+        test_frame1->set ({test_key}, test_val1);
 
         test_kvp_get_slot (i, test_frame1, test_val1, test_key);
         test_kvp_copy_compare (i, test_frame1, test_val1, test_key);
diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 1208425..3ee7882 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -5440,7 +5440,7 @@ parse_bayes_imap_info (std::string const & imap_bayes_entry)
     auto guid_start = imap_bayes_entry.size() - GUID_ENCODING_LENGTH;
     std::string keyword {imap_bayes_entry.substr (header_length + 1, guid_start - header_length - 2)};
     std::string account_guid {imap_bayes_entry.substr (guid_start)};
-    return {header, keyword, account_guid};
+    return std::tuple <std::string, std::string, std::string> {header, keyword, account_guid};
 }
 
 static void
@@ -5530,9 +5530,9 @@ gnc_account_delete_map_entry (Account *acc, char *full_category, gboolean empty)
     {
         xaccAccountBeginEdit (acc);
         if (empty)
-            qof_instance_slot_delete_if_empty (QOF_INSTANCE(acc), kvp_path);
+            qof_instance_slot_path_delete_if_empty (QOF_INSTANCE(acc), {kvp_path});
         else
-            qof_instance_slot_delete (QOF_INSTANCE(acc), kvp_path);
+            qof_instance_slot_path_delete (QOF_INSTANCE(acc), {kvp_path});
         PINFO("Account is '%s', path is '%s'", xaccAccountGetName (acc), kvp_path);
         qof_instance_set_dirty (QOF_INSTANCE(acc));
         xaccAccountCommitEdit (acc);
@@ -5620,7 +5620,7 @@ static std::vector<std::pair<std::string, KvpValue*>>
 get_new_guid_imap (Account * acc)
 {
     auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
-    auto slot = frame->get_slot (IMAP_FRAME_BAYES);
+    auto slot = frame->get_slot ({IMAP_FRAME_BAYES});
     if (!slot)
         return {};
     auto imap_frame = slot->get<KvpFrame*> ();
@@ -5640,9 +5640,9 @@ convert_imap_account_bayes_to_guid (Account *acc)
         return;
     auto new_imap = get_new_guid_imap(acc);
     xaccAccountBeginEdit(acc);
-    frame->set(IMAP_FRAME_BAYES, nullptr);
+    frame->set({IMAP_FRAME_BAYES}, nullptr);
     std::for_each(new_imap.begin(), new_imap.end(), [&frame] (std::pair<std::string, KvpValue*> const & entry) {
-        frame->set(entry.first.c_str(), entry.second);
+        frame->set({entry.first.c_str()}, entry.second);
     });
     qof_instance_set_dirty (QOF_INSTANCE (acc));
     xaccAccountCommitEdit(acc);
diff --git a/libgnucash/engine/gnc-aqbanking-templates.cpp b/libgnucash/engine/gnc-aqbanking-templates.cpp
index fe2c37d..ad6b8fd 100644
--- a/libgnucash/engine/gnc-aqbanking-templates.cpp
+++ b/libgnucash/engine/gnc-aqbanking-templates.cpp
@@ -106,13 +106,13 @@ KvpFrame*
 _GncABTransTempl::make_kvp_frame()
 {
     auto frame = new KvpFrame;
-    frame->set(TT_NAME, new KvpValue(m_name.c_str()));
-    frame->set(TT_RNAME, new KvpValue(m_recipient_name.c_str()));
-    frame->set(TT_RACC, new KvpValue(m_recipient_account.c_str()));
-    frame->set(TT_RBCODE, new KvpValue(m_recipient_bankcode.c_str()));
-    frame->set(TT_AMOUNT, new KvpValue(m_amount));
-    frame->set(TT_PURPOS, new KvpValue(m_purpose.c_str()));
-    frame->set(TT_PURPOSCT, new KvpValue(m_purpose_continuation.c_str()));
+    frame->set({TT_NAME}, new KvpValue(m_name.c_str()));
+    frame->set({TT_RNAME}, new KvpValue(m_recipient_name.c_str()));
+    frame->set({TT_RACC}, new KvpValue(m_recipient_account.c_str()));
+    frame->set({TT_RBCODE}, new KvpValue(m_recipient_bankcode.c_str()));
+    frame->set({TT_AMOUNT}, new KvpValue(m_amount));
+    frame->set({TT_PURPOS}, new KvpValue(m_purpose.c_str()));
+    frame->set({TT_PURPOSCT}, new KvpValue(m_purpose_continuation.c_str()));
     return frame;
 }
 
@@ -145,12 +145,12 @@ gnc_ab_trans_templ_list_new_from_book(QofBook *b)
     {
         KvpFrame *frame = static_cast<KvpValue*>(node->data)->get<KvpFrame*>();
         auto c_func = [frame](const char* key)
-            { auto slot = frame->get_slot(key);
+            { auto slot = frame->get_slot({key});
               return slot == nullptr ? std::string("") : std::string(slot->get<const char*>());};
         auto n_func = [frame](const char* key)
-            { auto slot = frame->get_slot(key);
+            { auto slot = frame->get_slot({key});
               return slot == nullptr ? gnc_numeric_zero() : slot->get<gnc_numeric>();};
-        auto amt_slot = frame->get_slot(TT_AMOUNT);
+        auto amt_slot = frame->get_slot({TT_AMOUNT});
         auto templ = new _GncABTransTempl (c_func(TT_NAME), c_func(TT_RNAME),
                                            c_func(TT_RACC), c_func(TT_RBCODE),
                                            n_func(TT_AMOUNT), c_func(TT_PURPOS),
diff --git a/libgnucash/engine/kvp-frame.cpp b/libgnucash/engine/kvp-frame.cpp
index eff478a..9687cc1 100644
--- a/libgnucash/engine/kvp-frame.cpp
+++ b/libgnucash/engine/kvp-frame.cpp
@@ -68,124 +68,90 @@ KvpFrameImpl::~KvpFrameImpl() noexcept
     m_valuemap.clear();
 }
 
-static inline Path
-make_vector(std::string key)
+KvpFrame *
+KvpFrame::get_child_frame_or_nullptr (Path const & path) noexcept
 {
-    Path path;
-    for (auto length = key.find(delim); length != std::string::npos;)
-    {
-        if (length != 0)
-            path.push_back(key.substr(0, length));
-        key = key.substr(length + 1);
-        length = key.find(delim);
-    }
-    if (!key.empty())
-	path.push_back(key);
-    return path;
+    if (!path.size ())
+        return this;
+    auto key = path.front ();
+    if (m_valuemap.find (key.c_str ()) == m_valuemap.end ())
+        return nullptr;
+    auto child = m_valuemap.at (key.c_str ())->get <KvpFrame *> ();
+    Path send;
+    std::copy (path.begin () + 1, path.end (), std::back_inserter (send));
+    return child->get_child_frame_or_nullptr (send);
 }
 
-/*
- * If the key is delimited, calls set(path) with the parsed result
- * otherwise, inserts the key and value locally and returns the
- * old value if there was one.
- */
-KvpValue*
-KvpFrameImpl::set(const char* key, KvpValue* value) noexcept
+KvpFrame *
+KvpFrame::get_child_frame_or_create (Path const & path) noexcept
 {
-    if (!key) return nullptr;
-    if (strchr(key, delim))
-        return set(make_vector(key), value);
-    KvpValue* ret {nullptr};
-    auto spot = m_valuemap.find(key);
-    if (spot != m_valuemap.end())
+    if (!path.size ())
+        return this;
+    auto key = path.front ();
+    auto spot = m_valuemap.find (key.c_str ());
+    if (spot == m_valuemap.end () || spot->second->get_type () != KvpValue::Type::FRAME)
+        delete set_impl (key.c_str (), new KvpValue {new KvpFrame});
+    Path send;
+    std::copy (path.begin () + 1, path.end (), std::back_inserter (send));
+    auto child_val = m_valuemap.at (key.c_str ());
+    auto child = child_val->get <KvpFrame *> ();
+    return child->get_child_frame_or_create (send);
+}
+
+
+KvpValue *
+KvpFrame::set_impl (std::string const & key, KvpValue * value) noexcept
+{
+    KvpValue * ret {};
+    auto spot = m_valuemap.find (key.c_str ());
+    if (spot != m_valuemap.end ())
     {
-        qof_string_cache_remove(spot->first);
+        qof_string_cache_remove (spot->first);
         ret = spot->second;
-        m_valuemap.erase(spot);
+        m_valuemap.erase (spot);
     }
-
     if (value)
     {
-        auto cachedkey =
-            static_cast<const char *>(qof_string_cache_insert(key));
-        m_valuemap.insert({cachedkey,value});
+        auto cachedkey = static_cast <char const *> (qof_string_cache_insert (key.c_str ()));
+        m_valuemap.emplace (cachedkey, value);
     }
-
     return ret;
 }
 
-static inline KvpFrameImpl*
-walk_path_or_nullptr(const KvpFrameImpl* frame, Path& path)
+KvpValue *
+KvpFrameImpl::set (Path path, KvpValue* value) noexcept
 {
-    KvpFrameImpl* cur_frame = const_cast<KvpFrameImpl*>(frame);
-    for(auto key:path)
-    {
-        auto slot = cur_frame->get_slot(key.c_str());
-        if (slot == nullptr || slot->get_type() != KvpValue::Type::FRAME)
-            return nullptr;
-        cur_frame = slot->get<KvpFrame*>();
-    }
-    return cur_frame;
+    auto key = path.back ();
+    path.pop_back ();
+    auto target = get_child_frame_or_nullptr (path);
+    if (!target)
+        return nullptr;
+    return target->set_impl (key, value);
 }
 
-/*
- * If the last path parameter has a delimiter, the path before that point is ignored,
- * and set is called with only the last parameter with the delimiter as the key.
- */
-KvpValue*
-KvpFrameImpl::set(Path path, KvpValue* value) noexcept
+KvpValue *
+KvpFrameImpl::set_path (Path path, KvpValue* value) noexcept
 {
-    auto last_key = path.back();
+    auto key = path.back();
     path.pop_back();
-    auto cur_frame = walk_path_or_nullptr(this, path);
-    if (cur_frame == nullptr)
+    auto target = get_child_frame_or_create (path);
+    if (!target)
         return nullptr;
-    if (last_key.find(delim) != std::string::npos)
-        return set(make_vector(last_key), value);
-    return cur_frame->set(last_key.c_str(), value);
+    return target->set_impl (key, value);
 }
 
-static inline KvpFrameImpl*
-walk_path_and_create(KvpFrameImpl* frame, Path path)
+KvpValue *
+KvpFrameImpl::get_slot (Path path) noexcept
 {
-     for(auto key:path)
-    {
-	if (key.empty())
-	    continue;
-        if (key.find(delim) != std::string::npos)
-        {
-            frame = walk_path_and_create(frame, make_vector(key));
-            continue;
-        }
-        auto slot = frame->get_slot(key.c_str());
-        if (slot == nullptr || slot->get_type() != KvpValue::Type::FRAME)
-        {
-            auto new_frame = new KvpFrame;
-            delete frame->set(key.c_str(), new KvpValue{new_frame});
-            frame = new_frame;
-            continue;
-        }
-        frame = slot->get<KvpFrame*>();
-    }
-    return frame;
-}
-
-KvpValue*
-KvpFrameImpl::set_path(const char* path, KvpValue* value) noexcept
-{
-    return set_path(make_vector(path), value);
-}
-
-KvpValue*
-KvpFrameImpl::set_path(Path path, KvpValue* value) noexcept
-{
-    auto cur_frame = this;
-    auto last_key = path.back();
+    auto key = path.back();
     path.pop_back();
-    cur_frame = walk_path_and_create(const_cast<KvpFrame*>(this), path);
-    if (last_key.find(delim) != std::string::npos)
-        return set_path(make_vector(last_key), value);
-    return cur_frame->set(last_key.c_str(), value);
+    auto target = get_child_frame_or_nullptr (path);
+    if (!target)
+        return nullptr;
+    auto spot = target->m_valuemap.find (key.c_str ());
+    if (spot != target->m_valuemap.end ())
+        return spot->second;
+    return nullptr;
 }
 
 std::string
@@ -231,32 +197,6 @@ KvpFrameImpl::get_keys() const noexcept
     return ret;
 }
 
-KvpValueImpl *
-KvpFrameImpl::get_slot(const char * key) const noexcept
-{
-    if (!key) return nullptr;
-    if (strchr(key, delim))
-        return get_slot(make_vector(key));
-    auto spot = m_valuemap.find(key);
-    if (spot == m_valuemap.end())
-        return nullptr;
-    return spot->second;
-}
-
-KvpValueImpl *
-KvpFrameImpl::get_slot(Path path) const noexcept
-{
-    auto last_key = path.back();
-    path.pop_back();
-    auto cur_frame = walk_path_or_nullptr(this, path);
-    if (cur_frame == nullptr)
-        return nullptr;
-    if (last_key.find(delim) != std::string::npos)
-        return get_slot(make_vector(last_key));
-    return cur_frame->get_slot(last_key.c_str());
-
-}
-
 int compare(const KvpFrameImpl * one, const KvpFrameImpl * two) noexcept
 {
     if (one && !two) return 1;
@@ -483,7 +423,7 @@ gnc_value_list_get_type (void)
 }
 
 void
-KvpFrame::flatten_kvp_impl(std::vector <std::string> path, std::vector <std::pair <std::vector <std::string>, KvpValue*>> & entries) const
+KvpFrame::flatten_kvp_impl(std::vector <std::string> path, std::vector <std::pair <std::vector <std::string>, KvpValue*>> & entries) const noexcept
 {
     for (auto const & entry : m_valuemap)
     {
@@ -504,7 +444,7 @@ KvpFrame::flatten_kvp_impl(std::vector <std::string> path, std::vector <std::pai
 }
 
 std::vector <std::pair <std::vector <std::string>, KvpValue*>>
-KvpFrame::flatten_kvp(void) const
+KvpFrame::flatten_kvp(void) const noexcept
 {
     std::vector <std::pair <std::vector <std::string>, KvpValue*>> ret;
     flatten_kvp_impl({}, ret);
diff --git a/libgnucash/engine/kvp-frame.hpp b/libgnucash/engine/kvp-frame.hpp
index 6bdb16f..32dd102 100644
--- a/libgnucash/engine/kvp-frame.hpp
+++ b/libgnucash/engine/kvp-frame.hpp
@@ -141,7 +141,7 @@ struct KvpFrameImpl
      * @param newvalue: The value to set at key.
      * @return The old value if there was one or nullptr.
      */
-    KvpValue* set(const char * key, KvpValue* newvalue) noexcept;
+    //KvpValue* set(const char * key, KvpValue* newvalue) noexcept;
     /**
      * Set the value with the key in a subframe following the keys in path,
      * replacing and returning the old value if it exists or nullptr if it
@@ -156,18 +156,6 @@ struct KvpFrameImpl
      * @return The old value if there was one or nullptr.
      */
     KvpValue* set(Path path, KvpValue* newvalue) noexcept;
-    /**
-     * Set the value with the key in a subframe following the keys in path,
-     * replacing and returning the old value if it exists or nullptr if it
-     * doesn't. Creates any missing intermediate frames. Takes
-     * ownership of new value and releases ownership of the returned old
-     * value. Values must be allocated on the free store with operator new.
-     * @param path: The path of subframes as a '/'-delimited string leading to
-     * the frame in which to insert/replace.
-     * @param newvalue: The value to set at key.
-     * @return The old value if there was one or nullptr.
-     */
-    KvpValue* set_path(const char* path, KvpValue* newvalue) noexcept;
      /**
      * Set the value with the key in a subframe following the keys in path,
      * replacing and returning the old value if it exists or nullptr if it
@@ -198,16 +186,11 @@ struct KvpFrameImpl
      */
     std::vector<std::string> get_keys() const noexcept;
 
-    /** Get the value for the key or nullptr if it doesn't exist.
-     * @param key: The key.
-     * @return The value at the key or nullptr.
-     */
-    KvpValue* get_slot(const char * key) const noexcept;
     /** Get the value for the tail of the path or nullptr if it doesn't exist.
      * @param path: Path of keys leading to the desired value.
      * @return The value at the key or nullptr.
      */
-    KvpValue* get_slot(Path keys) const noexcept;
+    KvpValue* get_slot(Path keys) noexcept;
 
     /**
      * proc is called with each of the immediate contents of this frame, passing it the key,
@@ -240,7 +223,7 @@ struct KvpFrameImpl
      * the frame-containing values.
      */
     std::vector <std::pair <std::vector <std::string>, KvpValue*>>
-    flatten_kvp(void) const;
+    flatten_kvp(void) const noexcept;
 
     /** Test for emptiness
      * @return true if the frame contains nothing.
@@ -251,7 +234,10 @@ struct KvpFrameImpl
     private:
     map_type m_valuemap;
 
-    void flatten_kvp_impl(std::vector <std::string>, std::vector <std::pair <std::vector <std::string>, KvpValue*>> &) const;
+    KvpFrame * get_child_frame_or_nullptr (Path const &) noexcept;
+    KvpFrame * get_child_frame_or_create (Path const &) noexcept;
+    void flatten_kvp_impl(std::vector <std::string>, std::vector <std::pair <std::vector <std::string>, KvpValue*>> &) const noexcept;
+    KvpValue * set_impl (std::string const &, KvpValue *) noexcept;
 };
 
 template<typename func_type>
diff --git a/libgnucash/engine/qofbook.cpp b/libgnucash/engine/qofbook.cpp
index 1694ec4..82f998e 100644
--- a/libgnucash/engine/qofbook.cpp
+++ b/libgnucash/engine/qofbook.cpp
@@ -1040,7 +1040,7 @@ GDate* qof_book_get_autoreadonly_gdate (const QofBook *book)
 const char*
 qof_book_get_string_option(const QofBook* book, const char* opt_name)
 {
-    auto slot = qof_instance_get_slots(QOF_INSTANCE (book))->get_slot(opt_name);
+    auto slot = qof_instance_get_slots(QOF_INSTANCE (book))->get_slot({opt_name});
     if (slot == nullptr)
         return nullptr;
     return slot->get<const char*>();
@@ -1052,9 +1052,9 @@ qof_book_set_string_option(QofBook* book, const char* opt_name, const char* opt_
     qof_book_begin_edit(book);
     auto frame = qof_instance_get_slots(QOF_INSTANCE(book));
     if (opt_val && (*opt_val != '\0'))
-        delete frame->set(opt_name, new KvpValue(g_strdup(opt_val)));
+        delete frame->set({opt_name}, new KvpValue(g_strdup(opt_val)));
     else
-        delete frame->set(opt_name, nullptr);
+        delete frame->set({opt_name}, nullptr);
     qof_instance_set_dirty (QOF_INSTANCE (book));
     qof_book_commit_edit(book);
 }
@@ -1086,7 +1086,7 @@ qof_book_get_features (QofBook *book)
     GHashTable *features = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                   NULL, g_free);
 
-    auto slot = frame->get_slot(GNC_FEATURES);
+    auto slot = frame->get_slot({GNC_FEATURES});
     if (slot != nullptr)
     {
         frame = slot->get<KvpFrame*>();
@@ -1100,11 +1100,11 @@ qof_book_set_feature (QofBook *book, const gchar *key, const gchar *descr)
 {
     KvpFrame *frame = qof_instance_get_slots (QOF_INSTANCE (book));
     KvpValue* feature = nullptr;
-    auto feature_slot = frame->get_slot(GNC_FEATURES);
+    auto feature_slot = frame->get_slot({GNC_FEATURES});
     if (feature_slot)
     {
         auto feature_frame = feature_slot->get<KvpFrame*>();
-        feature = feature_frame->get_slot(key);
+        feature = feature_frame->get_slot({key});
     }
     if (feature == nullptr || g_strcmp0 (feature->get<const char*>(), descr))
     {
@@ -1178,7 +1178,7 @@ qof_book_options_delete (QofBook *book, GSList *path)
         delete root->set_path(path_v, nullptr);
     }
     else
-        delete root->set_path(KVP_OPTION_PATH, nullptr);
+        delete root->set_path({KVP_OPTION_PATH}, nullptr);
 }
 
 /* QofObject function implementation and registration */
diff --git a/libgnucash/engine/qofinstance-p.h b/libgnucash/engine/qofinstance-p.h
index bce6ead..9fd5e4f 100644
--- a/libgnucash/engine/qofinstance-p.h
+++ b/libgnucash/engine/qofinstance-p.h
@@ -154,10 +154,7 @@ void qof_instance_kvp_merge_guids (const QofInstance *target,
                                    const QofInstance *donor, const char* path);
 gboolean qof_instance_has_slot (const QofInstance *inst, const char *path);
 void qof_instance_slot_var_delete (const QofInstance *, unsigned count, ...);
-void qof_instance_slot_delete (const QofInstance *inst, const char *path);
 void qof_instance_slot_var_delete_if_empty (const QofInstance *, unsigned count, ...);
-void qof_instance_slot_delete_if_empty (const QofInstance *inst,
-                                        const char *path);
 void qof_instance_foreach_slot (const QofInstance *inst, const char *path,
                                 void(*proc)(const char*, const GValue*, void*),
                                 void* data);
@@ -183,7 +180,7 @@ template<typename func_type, typename data_type>
 void qof_instance_foreach_slot_temp (QofInstance const * inst, std::string const & path,
         func_type const & func, data_type & data)
 {
-    auto slot = inst->kvp_data->get_slot(path.c_str());
+    auto slot = inst->kvp_data->get_slot({path});
     if (slot == nullptr || slot->get_type() != KvpValue::Type::FRAME)
         return;
     auto frame = slot->get<KvpFrame*>();
diff --git a/libgnucash/engine/qofinstance.cpp b/libgnucash/engine/qofinstance.cpp
index a222668..7a3b6bf 100644
--- a/libgnucash/engine/qofinstance.cpp
+++ b/libgnucash/engine/qofinstance.cpp
@@ -1144,8 +1144,8 @@ qof_instance_kvp_add_guid (const QofInstance *inst, const char* path,
     g_return_if_fail (inst->kvp_data != NULL);
 
     auto container = new KvpFrame;
-    container->set(key, new KvpValue(const_cast<GncGUID*>(guid)));
-    container->set("date", new KvpValue(time));
+    container->set({key}, new KvpValue(const_cast<GncGUID*>(guid)));
+    container->set({"date"}, new KvpValue(time));
     delete inst->kvp_data->set_path({path}, new KvpValue(container));
 }
 
@@ -1286,7 +1286,7 @@ bool qof_instance_has_path_slot (QofInstance const * inst, std::vector<std::stri
 gboolean
 qof_instance_has_slot (const QofInstance *inst, const char *path)
 {
-    return inst->kvp_data->get_slot(path) != NULL;
+    return inst->kvp_data->get_slot({path}) != NULL;
 }
 
 void qof_instance_slot_path_delete (QofInstance const * inst, std::vector<std::string> const & path)
@@ -1306,12 +1306,6 @@ qof_instance_slot_var_delete (QofInstance const *inst, unsigned count, ...)
     delete inst->kvp_data->set (path, nullptr);
 }
 
-void
-qof_instance_slot_delete (const QofInstance *inst, const char *path)
-{
-    delete inst->kvp_data->set(path, nullptr);
-}
-
 void qof_instance_slot_path_delete_if_empty (QofInstance const * inst, std::vector<std::string> const & path)
 {
     auto slot = inst->kvp_data->get_slot (path);
@@ -1341,18 +1335,6 @@ qof_instance_slot_var_delete_if_empty (QofInstance const *inst, unsigned count,
     }
 }
 
-void
-qof_instance_slot_delete_if_empty (const QofInstance *inst, const char *path)
-{
-    auto slot = inst->kvp_data->get_slot(path);
-    if (slot)
-    {
-        auto frame = slot->get<KvpFrame*>();
-        if (frame && frame->empty())
-            delete inst->kvp_data->set(path, nullptr);
-    }
-}
-
 std::vector <std::pair <std::string, KvpValue*>>
 qof_instance_get_slots_prefix (QofInstance const * inst, std::string const & prefix)
 {
@@ -1393,7 +1375,7 @@ qof_instance_foreach_slot (const QofInstance *inst, const char* path,
                            void (*proc)(const char*, const GValue*, void*),
                            void* data)
 {
-    auto slot = inst->kvp_data->get_slot(path);
+    auto slot = inst->kvp_data->get_slot({path});
     if (slot == nullptr || slot->get_type() != KvpValue::Type::FRAME)
         return;
     auto frame = slot->get<KvpFrame*>();
diff --git a/libgnucash/engine/test-core/test-engine-stuff.cpp b/libgnucash/engine/test-core/test-engine-stuff.cpp
index c4c4170..ab2cb02 100644
--- a/libgnucash/engine/test-core/test-engine-stuff.cpp
+++ b/libgnucash/engine/test-core/test-engine-stuff.cpp
@@ -381,7 +381,7 @@ get_random_kvp_frame_depth (gint depth)
 
         val_added = TRUE;
 
-        ret->set_path(key, val);
+        ret->set_path({key}, val);
 
         g_free(key);
     }
diff --git a/libgnucash/engine/test/gtest-import-map.cpp b/libgnucash/engine/test/gtest-import-map.cpp
index 1d5b693..d811574 100644
--- a/libgnucash/engine/test/gtest-import-map.cpp
+++ b/libgnucash/engine/test/gtest-import-map.cpp
@@ -254,12 +254,12 @@ TEST_F(ImapBayesTest, FindAccountBayes)
     auto acct2_guid = guid_to_string (xaccAccountGetGUID(t_expense_account2));
     auto value = new KvpValue(INT64_C(42));
 
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid).c_str(), value);
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid).c_str(), new KvpValue{*value});
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid).c_str(), new KvpValue{*value});
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid).c_str(), new KvpValue{*value});
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct1_guid).c_str(), new KvpValue{*value});
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct2_guid).c_str(), new KvpValue{*value});
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid}, value);
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid}, new KvpValue{*value});
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid}, new KvpValue{*value});
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid}, new KvpValue{*value});
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct1_guid}, new KvpValue{*value});
+    root->set_path({std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct2_guid}, new KvpValue{*value});
 
     auto account = gnc_account_imap_find_account_bayes(t_imap, t_list1);
     EXPECT_EQ(t_expense_account1, account);
@@ -292,29 +292,29 @@ TEST_F(ImapBayesTest, AddAccountBayes)
     auto root = qof_instance_get_slots(QOF_INSTANCE(t_bank_account));
     auto acct1_guid = guid_to_string (xaccAccountGetGUID(t_expense_account1));
     auto acct2_guid = guid_to_string (xaccAccountGetGUID(t_expense_account2));
-    auto value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-foo-bar").c_str());
+    auto value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-foo-bar"});
     auto check_account = [this](KvpValue* v) {
         return (v->get<const char*>(), this->t_imap->book); };
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct1_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct1_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct2_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct2_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct1_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct1_guid});
     EXPECT_EQ(nullptr, value);
 
     qof_instance_increase_editlevel(QOF_INSTANCE(t_bank_account));
     gnc_account_imap_add_account_bayes(t_imap, t_list2, t_expense_account2);
     qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
     qof_instance_reset_editlevel(QOF_INSTANCE(t_bank_account));
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid});
     EXPECT_EQ(2, value->get<int64_t>());
 }
 
@@ -335,43 +335,43 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
     auto val2 = new KvpValue(static_cast<int64_t>(5));
     auto val3 = new KvpValue(static_cast<int64_t>(2));
     // Test for existing entries, all will be 1
-    auto value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid).c_str());
+    auto value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid});
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid});
     EXPECT_EQ(1, value->get<int64_t>());
     // Set up some old entries
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "/token/with/slashes/" + "Asset-Bank").c_str(), val1);
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + "Asset-Bank#Bank").c_str(), new KvpValue{*val1});
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + "Asset>Bank#Bank").c_str(), val2);
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + pork + "/" + "Expense#Food").c_str(), new KvpValue{*val2});
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + sausage + "/" + "Expense#Drink").c_str(), val3);
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + "Expense#Food").c_str(), new KvpValue{*val2});
+    root->set_path({IMAP_FRAME_BAYES, "token", "with", "slashes", "Asset-Bank"}, val1);
+    root->set_path({IMAP_FRAME_BAYES, salt, "Asset-Bank#Bank"}, new KvpValue{*val1});
+    root->set_path({IMAP_FRAME_BAYES, salt, "Asset>Bank#Bank"}, val2);
+    root->set_path({IMAP_FRAME_BAYES, pork, "Expense#Food"}, new KvpValue{*val2});
+    root->set_path({IMAP_FRAME_BAYES, sausage, "Expense#Drink"}, val3);
+    root->set_path({IMAP_FRAME_BAYES, foo, "Expense#Food"}, new KvpValue{*val2});
     EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account)));
     EXPECT_TRUE(qof_instance_get_dirty_flag(QOF_INSTANCE(t_bank_account)));
     qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
     // Start Convert
     gnc_account_imap_convert_bayes (t_imap->book);
     // convert from 'Asset-Bank' to 'Asset-Bank' guid
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-token-with-slashes-" + acct3_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-token-with-slashes-" + acct3_guid});
     EXPECT_EQ(10, value->get<int64_t>());
     // convert from 'Asset-Bank#Bank' to 'Sav Bank' guid
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct4_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct4_guid});
     EXPECT_EQ(10, value->get<int64_t>());
     // convert from 'Expense#Food' to 'Food' guid
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + pork + "-" + acct1_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + pork + "-" + acct1_guid});
     EXPECT_EQ(5, value->get<int64_t>());
     // convert from 'Expense#Drink' to 'Drink' guid
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + sausage + "-" + acct2_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + sausage + "-" + acct2_guid});
     EXPECT_EQ(2, value->get<int64_t>());
     // convert from 'Expense#Food' to 'Food' guid but add to original value
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid).c_str());
+    value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid});
     EXPECT_EQ(5, value->get<int64_t>());
     // Check for run once flag
-    auto vals = book->get_slot("changed-bayesian-to-guid");
+    auto vals = book->get_slot({"changed-bayesian-to-guid"});
     EXPECT_STREQ("true", vals->get<const char*>());
     EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account)));
     EXPECT_TRUE(qof_instance_get_dirty_flag(QOF_INSTANCE(t_bank_account)));
diff --git a/libgnucash/engine/test/test-kvp-frame.cpp b/libgnucash/engine/test/test-kvp-frame.cpp
index d67639f..4a57c45 100644
--- a/libgnucash/engine/test/test-kvp-frame.cpp
+++ b/libgnucash/engine/test/test-kvp-frame.cpp
@@ -35,10 +35,10 @@ public:
         t_int_val{new KvpValue {INT64_C(15)}},
         t_str_val{new KvpValue{"a value"}}     {
         auto f1 = new KvpFrame;
-        t_root.set("top", new KvpValue{f1});
-        f1->set("first", t_int_val);
-        f1->set("second", new KvpValue{new KvpFrame});
-        f1->set("third", t_str_val);
+        t_root.set({"top"}, new KvpValue{f1});
+        f1->set({"first"}, t_int_val);
+        f1->set({"second"}, new KvpValue{new KvpFrame});
+        f1->set({"third"}, t_str_val);
     }
 protected:
     KvpFrameImpl t_root;
@@ -59,13 +59,12 @@ TEST_F (KvpFrameTest, SetLocal)
     auto v1 = new KvpValueImpl {15.0};
     auto v2 = new KvpValueImpl { (int64_t)52};
     const char* k1 = "first key";
-    const char* k2 = "first key/second key";
 
-    EXPECT_EQ (nullptr, f1->set (k1, v1));
+    EXPECT_EQ (nullptr, f1->set ({k1}, v1));
     auto first_frame = new KvpFrame;
-    EXPECT_EQ (v1, f1->set (k1, new KvpValue{first_frame}));
-    EXPECT_EQ (nullptr, f1->set(k2, v2));
-    EXPECT_EQ (v2, first_frame->get_slot("second key"));
+    EXPECT_EQ (v1, f1->set ({k1}, new KvpValue{first_frame}));
+    EXPECT_EQ (nullptr, f1->set({"first key", "second key"}, v2));
+    EXPECT_EQ (v2, first_frame->get_slot({"second key"}));
 
     delete f1; //this should also delete v2.
     delete v1;
@@ -88,15 +87,14 @@ TEST_F (KvpFrameTest, SetPath)
 
 TEST_F (KvpFrameTest, SetPathSlash)
 {
-    Path path1 {"top", "second/twenty", "twenty-first"};
+    Path path1 {"top", "second", "twenty", "twenty-first"};
     Path path2 {"top", "third", "thirty-first"};
     auto v1 = new KvpValueImpl {15.0};
     auto v2 = new KvpValueImpl { (int64_t)52};
-
     EXPECT_EQ (nullptr, t_root.set(path1, v1));
     EXPECT_EQ (nullptr, t_root.set(path1, v2));
-    auto second_frame = t_root.get_slot("top")->get<KvpFrame*>()->get_slot("second")->get<KvpFrame*>();
-    second_frame->set("twenty", new KvpValue{new KvpFrame});
+    auto second_frame = t_root.get_slot({"top"})->get<KvpFrame*>()->get_slot({"second"})->get<KvpFrame*>();
+    second_frame->set({"twenty"}, new KvpValue{new KvpFrame});
     EXPECT_EQ (nullptr, t_root.set(path1, v1));
     EXPECT_EQ (v1, t_root.set(path1, v2));
     EXPECT_EQ (v2, t_root.get_slot(path1));
@@ -104,16 +102,6 @@ TEST_F (KvpFrameTest, SetPathSlash)
     delete v1;
 }
 
-TEST_F (KvpFrameTest, SetPathIgnoreBeginEndSlash)
-{
-    Path path1 {"top", "/second/", "twenty-first"};
-    Path path2 {"top", "second", "twenty-first"};
-    auto v1 = new KvpValueImpl {15.0};
-
-    EXPECT_EQ (nullptr, t_root.set_path(path1, v1));
-    EXPECT_EQ (v1, t_root.get_slot(path2));
-}
-
 TEST_F (KvpFrameTest, SetPathWithCreate)
 {
     Path path1 {"top", "second", "twenty-first"};
@@ -130,7 +118,7 @@ TEST_F (KvpFrameTest, SetPathWithCreate)
 
 TEST_F (KvpFrameTest, SetPathWithCreateSlash)
 {
-    Path path1 {"top", "second/twenty", "twenty-first"};
+    Path path1 {"top", "second", "twenty", "twenty-first"};
     Path path2 {"top", "third", "thirty-first"};
     Path path1a {"top", "second", "twenty", "twenty-first"};
     auto v1 = new KvpValueImpl {15.0};
@@ -154,7 +142,7 @@ TEST_F (KvpFrameTest, GetKeys)
     EXPECT_EQ (keys.size (), 1ul);
 
     assert_contains (keys, k1);
-    auto frameval = t_root.get_slot(k1);
+    auto frameval = t_root.get_slot({k1});
     ASSERT_EQ(frameval->get_type(), KvpValue::Type::FRAME);
     keys = frameval->get<KvpFrame*>()->get_keys();
     assert_contains (keys, k2);
@@ -166,15 +154,13 @@ TEST_F (KvpFrameTest, GetLocalSlot)
     auto k1 = "first";
     auto k2 = "third";
     auto k3 = "doesn't exist";
-    auto k4 = "top/first";
-
-    auto frameval = t_root.get_slot("top");
+    auto frameval = t_root.get_slot({"top"});
     ASSERT_EQ(frameval->get_type(), KvpValue::Type::FRAME);
     auto f1 = frameval->get<KvpFrame*>();
-    EXPECT_EQ (t_int_val, f1->get_slot(k1));
-    EXPECT_EQ (t_str_val, f1->get_slot(k2));
-    EXPECT_EQ (nullptr, f1->get_slot(k3));
-    EXPECT_EQ (t_int_val, t_root.get_slot(k4));
+    EXPECT_EQ (t_int_val, f1->get_slot({k1}));
+    EXPECT_EQ (t_str_val, f1->get_slot({k2}));
+    EXPECT_EQ (nullptr, f1->get_slot({k3}));
+    EXPECT_EQ (t_int_val, t_root.get_slot({"top", "first"}));
 }
 
 TEST_F (KvpFrameTest, GetSlotPath)
@@ -182,7 +168,7 @@ TEST_F (KvpFrameTest, GetSlotPath)
     Path path1 {"top", "second", "twenty-first"};
     Path path2 {"top", "third", "thirty-first"};
     Path path3 {"top", "second", "twenty", "twenty-first"};
-    Path path3a {"top", "second/twenty", "twenty-first"};
+    Path path3a {"top", "second", "twenty", "twenty-first"};
     auto v1 = new KvpValueImpl {15.0};
     auto v2 = new KvpValueImpl { (int64_t)52};
 
@@ -198,7 +184,7 @@ TEST_F (KvpFrameTest, GetSlotPath)
 TEST_F (KvpFrameTest, Empty)
 {
     KvpFrameImpl f1, f2;
-    f2.set("value", new KvpValue {2.2});
+    f2.set({"value"}, new KvpValue {2.2});
     EXPECT_TRUE(f1.empty());
     EXPECT_FALSE(f2.empty());
 }
@@ -206,12 +192,12 @@ TEST_F (KvpFrameTest, Empty)
 TEST (KvpFrameTestForEachPrefix, for_each_prefix_1)
 {
     KvpFrame fr;
-    fr.set("one", new KvpValue{new KvpFrame});
-    fr.set("one/two", new KvpValue{new KvpFrame});
-    fr.set("top/two/three", new KvpValue {15.0});
-    fr.set("onetwo", new KvpValue{new KvpFrame});
-    fr.set("onetwo/three", new KvpValue {15.0});
-    fr.set("onetwothree", new KvpValue {(int64_t)52});
+    fr.set({"one"}, new KvpValue{new KvpFrame});
+    fr.set({"one", "two"}, new KvpValue{new KvpFrame});
+    fr.set({"top", "two", "three"}, new KvpValue {15.0});
+    fr.set({"onetwo"}, new KvpValue{new KvpFrame});
+    fr.set({"onetwo", "three"}, new KvpValue {15.0});
+    fr.set({"onetwothree"}, new KvpValue {(int64_t)52});
     unsigned count {};
     auto counter = [] (char const *, KvpValue*, unsigned & count) { ++count; };
     fr.for_each_slot_prefix("one", counter, count);
@@ -230,8 +216,8 @@ TEST (KvpFrameTestForEachPrefix, for_each_prefix_1)
 TEST (KvpFrameTestForEachPrefix, for_each_prefix_2)
 {
     KvpFrame fr;
-    fr.set("onetwo/three", new KvpValue {15.0});
-    fr.set("onethree", new KvpValue {(int64_t)52});
+    fr.set({"onetwo", "three"}, new KvpValue {15.0});
+    fr.set({"onethree"}, new KvpValue {(int64_t)52});
     unsigned count;
     fr.for_each_slot_prefix("onetwo", [](char const *, KvpValue * value, unsigned) {
             EXPECT_EQ(value->get_type(), KvpValue::Type::FRAME);
diff --git a/libgnucash/engine/test/utest-Split.cpp b/libgnucash/engine/test/utest-Split.cpp
index d60fbe1..704211d 100644
--- a/libgnucash/engine/test/utest-Split.cpp
+++ b/libgnucash/engine/test/utest-Split.cpp
@@ -735,12 +735,12 @@ test_xaccSplitDetermineGainStatus (Fixture *fixture, gconstpointer pData)
 
     fixture->split->gains = GAINS_STATUS_UNKNOWN;
     fixture->split->gains_split = NULL;
-    g_assert (fixture->split->inst.kvp_data->get_slot("gains_source") == NULL);
+    g_assert (fixture->split->inst.kvp_data->get_slot({"gains_source"}) == NULL);
     xaccSplitDetermineGainStatus (fixture->split);
     g_assert (fixture->split->gains_split == NULL);
     g_assert_cmpint (fixture->split->gains, ==, GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY);
 
-    fixture->split->inst.kvp_data->set("gains-source", new KvpValue(guid_copy(g_guid)));
+    fixture->split->inst.kvp_data->set({"gains-source"}, new KvpValue(guid_copy(g_guid)));
     g_assert (fixture->split->gains_split == NULL);
     fixture->split->gains = GAINS_STATUS_UNKNOWN;
     xaccSplitDetermineGainStatus (fixture->split);
@@ -1802,7 +1802,7 @@ test_xaccSplitGetOtherSplit (Fixture *fixture, gconstpointer pData)
     g_assert (xaccSplitGetOtherSplit (split1) == NULL);
 
     g_assert (xaccTransUseTradingAccounts (txn) == FALSE);
-    g_assert (split->inst.kvp_data->get_slot("lot-split") == NULL);
+    g_assert (split->inst.kvp_data->get_slot({"lot-split"}) == NULL);
     g_assert_cmpint (xaccTransCountSplits (txn), !=, 2);
     g_assert (xaccSplitGetOtherSplit (split) == NULL);
 
@@ -1813,18 +1813,18 @@ test_xaccSplitGetOtherSplit (Fixture *fixture, gconstpointer pData)
     xaccSplitSetParent (split2, txn);
     g_assert (xaccSplitGetOtherSplit (split) == NULL);
 
-    split->inst.kvp_data->set("lot-split", kvpnow);
-    g_assert (split->inst.kvp_data->get_slot("lot-split"));
+    split->inst.kvp_data->set({"lot-split"}, kvpnow);
+    g_assert (split->inst.kvp_data->get_slot({"lot-split"}));
     g_assert (xaccSplitGetOtherSplit (split) == NULL);
 
-    split1->inst.kvp_data->set("lot-split", kvpnow);
-    g_assert (split1->inst.kvp_data->get_slot("lot-split"));
+    split1->inst.kvp_data->set({"lot-split"}, kvpnow);
+    g_assert (split1->inst.kvp_data->get_slot({"lot-split"}));
     g_assert (xaccSplitGetOtherSplit (split) == split2);
 
-    split->inst.kvp_data->set("lot-split", NULL);
-    g_assert (split->inst.kvp_data->get_slot("lot-split") == NULL);
-    split1->inst.kvp_data->set("lot-split", NULL);
-    g_assert (split1->inst.kvp_data->get_slot("lot-split") == NULL);
+    split->inst.kvp_data->set({"lot-split"}, NULL);
+    g_assert (split->inst.kvp_data->get_slot({"lot-split"}) == NULL);
+    split1->inst.kvp_data->set({"lot-split"}, NULL);
+    g_assert (split1->inst.kvp_data->get_slot({"lot-split"}) == NULL);
     qof_book_begin_edit (book);
     qof_instance_set (QOF_INSTANCE (book),
 		      "trading-accts", "t",
diff --git a/libgnucash/engine/test/utest-Transaction.cpp b/libgnucash/engine/test/utest-Transaction.cpp
index a95a5ac..c322c66 100644
--- a/libgnucash/engine/test/utest-Transaction.cpp
+++ b/libgnucash/engine/test/utest-Transaction.cpp
@@ -153,8 +153,8 @@ setup (Fixture *fixture, gconstpointer pData)
         xaccTransSetCurrency (txn, fixture->curr);
         xaccSplitSetParent (split1, txn);
         xaccSplitSetParent (split2, txn);
-        frame->set(trans_notes_str, new KvpValue("Salt pork sausage"));
-        frame->set_path("/qux/quux/corge", new KvpValue(123.456));
+        frame->set({trans_notes_str}, new KvpValue("Salt pork sausage"));
+        frame->set_path({"qux", "quux", "corge"}, new KvpValue(123.456));
         qof_instance_set_slots (QOF_INSTANCE (txn), frame);
     }
     xaccTransCommitEdit (txn);
@@ -562,7 +562,7 @@ test_dupe_trans (Fixture *fixture, gconstpointer pData)
 
     oldtxn->date_posted = posted;
     oldtxn->date_entered = entered;
-    oldtxn->inst.kvp_data->set("/foo/bar/baz",
+    oldtxn->inst.kvp_data->set({"foo", "bar", "baz"},
                                new KvpValue("The Great Waldo Pepper"));
 
     newtxn = fixture->func->dupe_trans (oldtxn);
@@ -881,7 +881,7 @@ test_xaccTransEqual (Fixture *fixture, gconstpointer pData)
     g_free(clone->description);
     clone->description = static_cast<char*>(CACHE_INSERT ("Waldo Pepper"));
     auto frame = qof_instance_get_slots (QOF_INSTANCE (clone));
-    frame->set("/qux/quux/corge", new KvpValue(654.321));
+    frame->set({"qux", "quux", "corge"}, new KvpValue(654.321));
     xaccTransCommitEdit (clone);
     g_free (cleanup->msg);
     g_free (check->msg);
@@ -893,7 +893,7 @@ test_xaccTransEqual (Fixture *fixture, gconstpointer pData)
     xaccTransBeginEdit (clone);
     cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
     clone->description = static_cast<char*>(CACHE_INSERT ("Waldo Pepper"));
-    frame->set("/qux/quux/corge", new KvpValue(123.456));
+    frame->set({"qux", "quux", "corge"}, new KvpValue(123.456));
     xaccTransCommitEdit (clone);
     g_free (cleanup->msg);
     g_free (check->msg);
@@ -1858,22 +1858,22 @@ test_xaccTransVoid (Fixture *fixture, gconstpointer pData)
     /* Actual function variables start here. */
     auto frame = fixture->txn->inst.kvp_data;
     auto void_reason = "Voided for Unit Test";
-    auto txn_notes = g_strdup (frame->get_slot(trans_notes_str)->get<const char*>());
+    auto txn_notes = g_strdup (frame->get_slot({trans_notes_str})->get<const char*>());
     Timespec now = timespec_now ();
     char iso8601_str[ISO_DATELENGTH + 1] = "";
     GList *split = NULL;
 
     xaccTransVoid (fixture->txn, void_reason);
-    g_assert_cmpstr (frame->get_slot(trans_notes_str)->get<const char*>(), ==,
+    g_assert_cmpstr (frame->get_slot({trans_notes_str})->get<const char*>(), ==,
                      "Voided transaction");
-    g_assert_cmpstr (frame->get_slot(void_former_notes_str)->get<const char*>(),
+    g_assert_cmpstr (frame->get_slot({void_former_notes_str})->get<const char*>(),
                      ==, txn_notes);
-    g_assert_cmpstr (frame->get_slot(void_reason_str)->get<const char*>(), ==,
+    g_assert_cmpstr (frame->get_slot({void_reason_str})->get<const char*>(), ==,
                      void_reason);
     gnc_timespec_to_iso8601_buff (now, iso8601_str);
-    g_assert_cmpstr (frame->get_slot(void_time_str)->get<const char*>(), ==,
+    g_assert_cmpstr (frame->get_slot({void_time_str})->get<const char*>(), ==,
                      iso8601_str);
-    g_assert_cmpstr (frame->get_slot(TRANS_READ_ONLY_REASON)->get<const char*>(),
+    g_assert_cmpstr (frame->get_slot({TRANS_READ_ONLY_REASON})->get<const char*>(),
                      ==, "Transaction Voided");
     for (split = fixture->txn->splits; split; split=g_list_next (split))
     {
@@ -1883,12 +1883,12 @@ test_xaccTransVoid (Fixture *fixture, gconstpointer pData)
 
     xaccTransUnvoid (fixture->txn);
 
-    g_assert_cmpstr (frame->get_slot(trans_notes_str)->get<const char*>(), ==,
+    g_assert_cmpstr (frame->get_slot({trans_notes_str})->get<const char*>(), ==,
                      txn_notes);
-    g_assert (frame->get_slot(void_former_notes_str) == NULL);
-    g_assert (frame->get_slot(void_reason_str) == NULL);
-    g_assert (frame->get_slot(void_time_str) == NULL);
-    g_assert (frame->get_slot(TRANS_READ_ONLY_REASON) == NULL);
+    g_assert (frame->get_slot({void_former_notes_str}) == NULL);
+    g_assert (frame->get_slot({void_reason_str}) == NULL);
+    g_assert (frame->get_slot({void_time_str}) == NULL);
+    g_assert (frame->get_slot({TRANS_READ_ONLY_REASON}) == NULL);
     for (split = fixture->txn->splits; split; split=g_list_next (split))
     {
         g_assert (!gnc_numeric_zero_p (((Split*)(split->data))->value));
@@ -1909,7 +1909,7 @@ test_xaccTransReverse (Fixture *fixture, gconstpointer pData)
     auto frame = fixture->txn->inst.kvp_data;
     GList *orig_splits = NULL, *rev_splits = NULL;
 
-    g_assert (guid_equal (frame->get_slot(TRANS_REVERSED_BY)->get<GncGUID*>(),
+    g_assert (guid_equal (frame->get_slot({TRANS_REVERSED_BY})->get<GncGUID*>(),
                           xaccTransGetGUID (rev)));
 
     g_assert (!qof_instance_is_dirty (QOF_INSTANCE (rev))); //Cleared by commit

commit 2cda65e01237db48bf5399bfb1b1bdbce156830f
Author: lmat <dartme18 at gmail.com>
Date:   Fri Nov 3 21:27:48 2017 -0400

    Added test for and corrected get_bayes_info

diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index b7aaef0..1208425 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -5432,60 +5432,39 @@ build_non_bayes (const char *key, const GValue *value, gpointer user_data)
     g_free (guid_string);
 }
 
-static void
-build_bayes_layer_two (const char *key, KvpValue * val, imap_info imapInfo)
+static std::tuple<std::string, std::string, std::string>
+parse_bayes_imap_info (std::string const & imap_bayes_entry)
 {
-    QofBook     *book;
-    Account     *map_account = NULL;
-    GncGUID     *guid;
-    gchar       *kvp_path;
-    gchar       *count;
-    struct imap_info *imapInfo_node;
-    // Get the book
-    book = qof_instance_get_book (imapInfo.source_account);
-    if (val->get_type() == KvpValue::Type::INT64)
-    {
-        PINFO("build_bayes_layer_two: account '%s', token_count: '%" G_GINT64_FORMAT "'",
-                                  key, val->get<int64_t>());
-        count = g_strdup_printf ("%" G_GINT64_FORMAT, val->get<int64_t>());
-    }
-    else
-        count = g_strdup ("0");
-    kvp_path = g_strconcat (imapInfo.category_head, "/", key, NULL);
-    PINFO("build_bayes_layer_two: kvp_path is '%s'", kvp_path);
-    guid = g_new (GncGUID, 1);
-    if (string_to_guid (key, guid))
-        map_account = xaccAccountLookup (guid, book);
-    g_free (guid);
-    imapInfo_node = static_cast <imap_info*> (g_malloc(sizeof(*imapInfo_node)));
-    imapInfo_node->source_account = imapInfo.source_account;
-    imapInfo_node->map_account    = map_account;
-    imapInfo_node->full_category  = g_strdup (kvp_path);
-    imapInfo_node->match_string   = g_strdup (imapInfo.match_string);
-    imapInfo_node->category_head  = g_strdup (imapInfo.category_head);
-    imapInfo_node->count          = g_strdup (count);
-    imapInfo.list = g_list_append (imapInfo.list, imapInfo_node);
-    g_free (kvp_path);
-    g_free (count);
+    auto header_length = strlen (IMAP_FRAME_BAYES);
+    std::string header {imap_bayes_entry.substr (0, header_length)};
+    auto guid_start = imap_bayes_entry.size() - GUID_ENCODING_LENGTH;
+    std::string keyword {imap_bayes_entry.substr (header_length + 1, guid_start - header_length - 2)};
+    std::string account_guid {imap_bayes_entry.substr (guid_start)};
+    return {header, keyword, account_guid};
 }
 
 static void
 build_bayes (const char *key, KvpValue * value, imap_info & imapInfo)
 {
-    struct imap_info imapInfol2;
-    PINFO("build_bayes: match string '%s'", (char*)key);
-
-    std::string prefix {g_strdup_printf (IMAP_FRAME_BAYES "-%s", key)};
-    PINFO("build_bayes: prefix is '%s', key '%s'", prefix.c_str(), key);
-    imapInfol2.source_account = imapInfo.source_account;
-    imapInfol2.match_string   = g_strdup (key);
-    imapInfol2.category_head  = g_strdup (prefix.c_str());
-    imapInfol2.list           = imapInfo.list;
-    qof_instance_foreach_slot_prefix (QOF_INSTANCE(imapInfo.source_account), prefix,
-                               build_bayes_layer_two, imapInfol2);
-    imapInfo.list = imapInfol2.list;
-    g_free (imapInfol2.match_string);
-    g_free (imapInfol2.category_head);
+    auto slots = qof_instance_get_slots_prefix (QOF_INSTANCE (imapInfo.source_account), IMAP_FRAME_BAYES);
+    if (!slots.size()) return;
+    for (auto const & entry : slots)
+    {
+        auto parsed_key = parse_bayes_imap_info (entry.first);
+        auto temp_guid = gnc::GUID::from_string (std::get <2> (parsed_key));
+        GncGUID guid = temp_guid;
+        auto map_account = xaccAccountLookup (&guid, gnc_account_get_book (imapInfo.source_account));
+        std::string category_head {std::get <0> (parsed_key) + "-" + std::get <1> (parsed_key)};
+        auto imap_node = static_cast <imap_info*> (g_malloc (sizeof (imap_info)));
+        auto count = entry.second->get <int64_t> ();
+        imap_node->source_account = imapInfo.source_account;
+        imap_node->map_account = map_account;
+        imap_node->full_category = g_strdup (key);
+        imap_node->match_string = g_strdup (std::get <1> (parsed_key).c_str ());
+        imap_node->category_head = g_strdup (category_head.c_str ());
+        imap_node->count = g_strdup_printf ("%" G_GINT64_FORMAT, count);
+        imapInfo.list = g_list_append (imapInfo.list, imap_node);
+    };
 }
 
 GList *
@@ -5498,7 +5477,6 @@ gnc_account_imap_get_info_bayes (Account *acc)
     return imapInfo.list;
 }
 
-
 GList *
 gnc_account_imap_get_info (Account *acc, const char *category)
 {
diff --git a/libgnucash/engine/qofinstance-p.h b/libgnucash/engine/qofinstance-p.h
index a54a581..bce6ead 100644
--- a/libgnucash/engine/qofinstance-p.h
+++ b/libgnucash/engine/qofinstance-p.h
@@ -173,8 +173,9 @@ bool qof_instance_has_path_slot (QofInstance const *, std::vector<std::string> c
 void qof_instance_slot_path_delete (QofInstance const *, std::vector<std::string> const &);
 
 void qof_instance_slot_path_delete_if_empty (QofInstance const *, std::vector<std::string> const &);
+
 /** Returns all keys that match the given prefix and their corresponding values.*/
-std::map<std::string, KvpValue*>
+std::vector <std::pair <std::string, KvpValue*>>
 qof_instance_get_slots_prefix (QofInstance const *, std::string const & prefix);
 
 /* Don't pass nullptr as the function */
diff --git a/libgnucash/engine/qofinstance.cpp b/libgnucash/engine/qofinstance.cpp
index 64826d5..a222668 100644
--- a/libgnucash/engine/qofinstance.cpp
+++ b/libgnucash/engine/qofinstance.cpp
@@ -1353,6 +1353,17 @@ qof_instance_slot_delete_if_empty (const QofInstance *inst, const char *path)
     }
 }
 
+std::vector <std::pair <std::string, KvpValue*>>
+qof_instance_get_slots_prefix (QofInstance const * inst, std::string const & prefix)
+{
+    std::vector <std::pair <std::string, KvpValue*>> ret;
+    inst->kvp_data->for_each_slot_temp ([&prefix, &ret] (std::string const & key, KvpValue * val) {
+        if (key.find (prefix) == 0)
+            ret.emplace_back (key, val);
+    });
+    return ret;
+}
+
 namespace {
 struct wrap_param
 {
@@ -1360,6 +1371,7 @@ struct wrap_param
     void *user_data;
 };
 }
+
 static void
 wrap_gvalue_function (const char* key, KvpValue *val, wrap_param & param)
 {
diff --git a/libgnucash/engine/test/gtest-import-map.cpp b/libgnucash/engine/test/gtest-import-map.cpp
index 117fe59..1d5b693 100644
--- a/libgnucash/engine/test/gtest-import-map.cpp
+++ b/libgnucash/engine/test/gtest-import-map.cpp
@@ -381,11 +381,30 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
 TEST_F (ImapBayesTest, import_map_with_delimiters)
 {
     GList * tokens {nullptr};
-    tokens = g_list_prepend(tokens, const_cast<char*>("one/two/three"));
-    gnc_account_imap_add_account_bayes(t_imap, tokens, t_expense_account1);
-    gnc_account_imap_add_account_bayes(t_imap, tokens, t_expense_account1);
-    gnc_account_imap_add_account_bayes(t_imap, tokens, t_expense_account1);
+    tokens = g_list_prepend (tokens, const_cast<char*> ("one/two/three"));
+    gnc_account_imap_add_account_bayes (t_imap, tokens, t_expense_account1);
+    gnc_account_imap_add_account_bayes (t_imap, tokens, t_expense_account1);
+    gnc_account_imap_add_account_bayes (t_imap, tokens, t_expense_account1);
+    auto account = gnc_account_imap_find_account_bayes (t_imap, tokens);
+    EXPECT_EQ (account, t_expense_account1);
+}
 
+TEST_F (ImapBayesTest, get_bayes_info)
+{
+    GList * tokens {nullptr};
+    tokens = g_list_prepend (tokens, const_cast <char*> ("one/two/three"));
+    gnc_account_imap_add_account_bayes(t_imap, tokens, t_expense_account1);
     auto account = gnc_account_imap_find_account_bayes (t_imap, tokens);
     EXPECT_EQ (account, t_expense_account1);
+    auto infos = gnc_account_imap_get_info_bayes (t_bank_account);
+    EXPECT_EQ (g_list_first (infos), g_list_last (infos));
+    auto info = static_cast <imap_info*> (g_list_first (infos)->data);
+    EXPECT_EQ (info->source_account, t_bank_account);
+    EXPECT_EQ (info->map_account, t_expense_account1);
+    auto acct1_guid = guid_to_string (xaccAccountGetGUID(t_expense_account1)); //Food
+    EXPECT_STREQ (info->full_category, (std::string {IMAP_FRAME_BAYES} + "-one-two-three-" + acct1_guid).c_str ());
+    EXPECT_STREQ (info->match_string, "one-two-three");
+    EXPECT_STREQ (info->category_head, (std::string {IMAP_FRAME_BAYES} + "-one-two-three").c_str ());
+    EXPECT_STREQ (info->count, "1");
 }
+

commit 9d7ec35ce5ff59ffe5cf0bf65b1623bea5f52422
Author: lmat <dartme18 at gmail.com>
Date:   Thu Nov 2 15:42:22 2017 -0400

    Removed qof_instance_set_kvp, qof_instance_get_kvp
    
    And replaced them with versions that take lists of key path elements.
    This is in an effort to eliminate the parsing of kvp keys.

diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 8ce126d..b7aaef0 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -406,34 +406,27 @@ gnc_account_get_property (GObject         *object,
     case PROP_SORT_REVERSED:
         g_value_set_boolean(value, xaccAccountGetSortReversed(account));
     case PROP_LOT_NEXT_ID:
-        key = "lot-mgmt/next-id";
         /* Pre-set the value in case the frame is empty */
         g_value_set_int64 (value, 0);
-        qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {"lot-mgmt", "next-id"});
         break;
     case PROP_ONLINE_ACCOUNT:
-        key = "online_id";
-        qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {"online_id"});
         break;
     case PROP_OFX_INCOME_ACCOUNT:
-        key = KEY_ASSOC_INCOME_ACCOUNT;
-        qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {KEY_ASSOC_INCOME_ACCOUNT});
         break;
     case PROP_AB_ACCOUNT_ID:
-        key = AB_KEY "/" AB_ACCOUNT_ID;
-        qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_ACCOUNT_ID});
         break;
     case PROP_AB_ACCOUNT_UID:
-        key = AB_KEY "/" AB_ACCOUNT_UID;
-        qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_ACCOUNT_UID});
         break;
     case PROP_AB_BANK_CODE:
-        key = AB_KEY "/" AB_BANK_CODE;
-        qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_BANK_CODE});
         break;
     case PROP_AB_TRANS_RETRIEVAL:
-        key = AB_KEY "/" AB_TRANS_RETRIEVAL;
-        qof_instance_get_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_get_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_TRANS_RETRIEVAL});
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -449,10 +442,7 @@ gnc_account_set_property (GObject         *object,
 {
     Account *account;
     gnc_numeric *number;
-    const gchar *key = NULL;
-
     g_return_if_fail(GNC_IS_ACCOUNT(object));
-
     account = GNC_ACCOUNT(object);
     if (prop_id < PROP_RUNTIME_0)
         g_assert (qof_instance_get_editlevel(account));
@@ -540,32 +530,25 @@ gnc_account_set_property (GObject         *object,
     case PROP_SORT_REVERSED:
         xaccAccountSetSortReversed(account, g_value_get_boolean(value));
     case PROP_LOT_NEXT_ID:
-        key = "lot-mgmt/next-id";
-        qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {"lot-mgmt", "next-id"});
         break;
     case PROP_ONLINE_ACCOUNT:
-        key = "online_id";
-        qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {"online_id"});
         break;
     case PROP_OFX_INCOME_ACCOUNT:
-        key = KEY_ASSOC_INCOME_ACCOUNT;
-        qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {KEY_ASSOC_INCOME_ACCOUNT});
         break;
     case PROP_AB_ACCOUNT_ID:
-        key = AB_KEY "/" AB_ACCOUNT_ID;
-        qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_ACCOUNT_ID});
         break;
     case PROP_AB_ACCOUNT_UID:
-        key = AB_KEY "/" AB_ACCOUNT_UID;
-        qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_ACCOUNT_UID});
         break;
     case PROP_AB_BANK_CODE:
-        key = AB_KEY "/" AB_BANK_CODE;
-        qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_BANK_CODE});
         break;
     case PROP_AB_TRANS_RETRIEVAL:
-        key = AB_KEY "/" AB_TRANS_RETRIEVAL;
-        qof_instance_set_kvp (QOF_INSTANCE (account), key, value);
+        qof_instance_set_path_kvp (QOF_INSTANCE (account), value, {AB_KEY, AB_TRANS_RETRIEVAL});
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -2310,20 +2293,20 @@ set_kvp_string_tag (Account *acc, const char *tag, const char *value)
     if (value)
     {
         gchar *tmp = g_strstrip(g_strdup(value));
-	if (strlen (tmp))
-	{
-	     GValue v = G_VALUE_INIT;
-	     g_value_init (&v, G_TYPE_STRING);
-	     g_value_set_string (&v, tmp);
-	     qof_instance_set_kvp (QOF_INSTANCE (acc), tag , &v);
-	}
-	else
-	     qof_instance_set_kvp (QOF_INSTANCE (acc), tag, NULL);
+        if (strlen (tmp))
+        {
+            GValue v = G_VALUE_INIT;
+            g_value_init (&v, G_TYPE_STRING);
+            g_value_set_string (&v, tmp);
+            qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {tag});
+        }
+        else
+            qof_instance_set_path_kvp (QOF_INSTANCE (acc), NULL, {tag});
         g_free(tmp);
     }
     else
     {
-	 qof_instance_set_kvp (QOF_INSTANCE (acc), tag, NULL);
+         qof_instance_set_path_kvp (QOF_INSTANCE (acc), NULL, {tag});
     }
     mark_account (acc);
     xaccAccountCommitEdit(acc);
@@ -2334,7 +2317,7 @@ get_kvp_string_tag (const Account *acc, const char *tag)
 {
     GValue v = G_VALUE_INIT;
     if (acc == NULL || tag == NULL) return NULL;
-    qof_instance_get_kvp (QOF_INSTANCE (acc), tag, &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE (acc), &v, {tag});
     return G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
 }
 
@@ -2359,7 +2342,7 @@ xaccAccountSetSortOrder (Account *acc, const char *str)
 void
 xaccAccountSetSortReversed (Account *acc, gboolean sortreversed)
 {
-     set_kvp_string_tag (acc, "sort-reversed", sortreversed ? "true" : NULL);
+    set_kvp_string_tag (acc, "sort-reversed", sortreversed ? "true" : NULL);
 }
 
 static void
@@ -2507,7 +2490,7 @@ DxaccAccountSetCurrency (Account * acc, gnc_commodity * currency)
     if ((!acc) || (!currency)) return;
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, s);
-    qof_instance_set_kvp (QOF_INSTANCE (acc), "old-currency", &v);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {"old-currency"});
     mark_account (acc);
     xaccAccountCommitEdit(acc);
 
@@ -3142,7 +3125,7 @@ DxaccAccountGetCurrency (const Account *acc)
     gnc_commodity_table *table;
 
     if (!acc) return NULL;
-    qof_instance_get_kvp (QOF_INSTANCE(acc), "old-currency", &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {"old-currency"});
     if (G_VALUE_HOLDS_STRING (&v))
         s = g_value_get_string (&v);
     if (!s) return NULL;
@@ -3809,7 +3792,7 @@ xaccAccountForEachLot(const Account *acc,
 }
 
 static void
-set_boolean_key (Account *acc, const char* key, gboolean option)
+set_boolean_key (Account *acc, std::vector<std::string> const & path, gboolean option)
 {
     GValue v = G_VALUE_INIT;
     g_return_if_fail(GNC_IS_ACCOUNT(acc));
@@ -3817,17 +3800,17 @@ set_boolean_key (Account *acc, const char* key, gboolean option)
     g_value_init (&v, G_TYPE_BOOLEAN);
     g_value_set_boolean (&v, option);
     xaccAccountBeginEdit (acc);
-    qof_instance_set_kvp (QOF_INSTANCE (acc),key , &v);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, path);
     mark_account (acc);
     xaccAccountCommitEdit (acc);
 }
 
 static gboolean
-boolean_from_key (const Account *acc, const char *key)
+boolean_from_key (const Account *acc, std::vector<std::string> const & path)
 {
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
-    qof_instance_get_kvp (QOF_INSTANCE(acc), key, &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, path);
     if (G_VALUE_HOLDS_INT64 (&v))
         return g_value_get_int64 (&v) != 0;
     if (G_VALUE_HOLDS_BOOLEAN (&v))
@@ -3844,13 +3827,13 @@ boolean_from_key (const Account *acc, const char *key)
 gboolean
 xaccAccountGetTaxRelated (const Account *acc)
 {
-    return boolean_from_key(acc, "tax-related");
+    return boolean_from_key(acc, {"tax-related"});
 }
 
 void
 xaccAccountSetTaxRelated (Account *acc, gboolean tax_related)
 {
-    set_boolean_key(acc, "tax-related", tax_related);
+    set_boolean_key(acc, {"tax-related"}, tax_related);
 }
 
 const char *
@@ -3858,7 +3841,7 @@ xaccAccountGetTaxUSCode (const Account *acc)
 {
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
-    qof_instance_get_kvp (QOF_INSTANCE(acc), "/tax-US/code", &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {"tax-US", "code"});
     return G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
 }
 
@@ -3871,7 +3854,7 @@ xaccAccountSetTaxUSCode (Account *acc, const char *code)
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, code);
     xaccAccountBeginEdit (acc);
-    qof_instance_set_kvp (QOF_INSTANCE (acc), "/tax-US/code", &v);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {"tax-US", "code"});
     mark_account (acc);
     xaccAccountCommitEdit (acc);
 }
@@ -3881,8 +3864,7 @@ xaccAccountGetTaxUSPayerNameSource (const Account *acc)
 {
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
-    qof_instance_get_kvp (QOF_INSTANCE(acc),
-                          "/tax-US/payer-name-source", &v);
+    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;
  }
 
@@ -3895,7 +3877,7 @@ xaccAccountSetTaxUSPayerNameSource (Account *acc, const char *source)
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, source);
     xaccAccountBeginEdit (acc);
-    qof_instance_set_kvp (QOF_INSTANCE (acc), "/tax-US/payer-name-source", &v);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {"tax-US", "payer-name-source"});
     mark_account (acc);
     xaccAccountCommitEdit (acc);
 }
@@ -3906,7 +3888,7 @@ xaccAccountGetTaxUSCopyNumber (const Account *acc)
     gint64 copy_number = 0;
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
-    qof_instance_get_kvp (QOF_INSTANCE(acc), "/tax-US/copy-number", &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {"tax-US", "copy-number"});
     if (G_VALUE_HOLDS_INT64 (&v))
         copy_number = g_value_get_int64 (&v);
 
@@ -3923,11 +3905,11 @@ xaccAccountSetTaxUSCopyNumber (Account *acc, gint64 copy_number)
         GValue v = G_VALUE_INIT;
         g_value_init (&v, G_TYPE_INT64);
         g_value_set_int64 (&v, copy_number);
-        qof_instance_set_kvp (QOF_INSTANCE (acc), "/tax-US/copy-number", &v);
+        qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {"tax-US", "copy-number"});
     }
     else
     {
-        qof_instance_set_kvp (QOF_INSTANCE (acc), "/tax-US/copy-number", NULL);
+        qof_instance_set_path_kvp (QOF_INSTANCE (acc), nullptr, {"tax-US", "copy-number"});
     }
     mark_account (acc);
     xaccAccountCommitEdit (acc);
@@ -3939,13 +3921,13 @@ xaccAccountSetTaxUSCopyNumber (Account *acc, gint64 copy_number)
 gboolean
 xaccAccountGetPlaceholder (const Account *acc)
 {
-    return boolean_from_key(acc, "placeholder");
+    return boolean_from_key(acc, {"placeholder"});
 }
 
 void
 xaccAccountSetPlaceholder (Account *acc, gboolean val)
 {
-    set_boolean_key(acc, "placeholder", val);
+    set_boolean_key(acc, {"placeholder"}, val);
 }
 
 GNCPlaceholderType
@@ -3975,13 +3957,13 @@ xaccAccountGetDescendantPlaceholder (const Account *acc)
 gboolean
 xaccAccountGetHidden (const Account *acc)
 {
-    return boolean_from_key (acc, "hidden");
+    return boolean_from_key (acc, {"hidden"});
 }
 
 void
 xaccAccountSetHidden (Account *acc, gboolean val)
 {
-    set_boolean_key (acc, "hidden", val);
+    set_boolean_key (acc, {"hidden"}, val);
 }
 
 gboolean
@@ -4312,7 +4294,7 @@ xaccAccountGetReconcileLastDate (const Account *acc, time64 *last_date)
     gint64 date = 0;
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
-    qof_instance_get_kvp (QOF_INSTANCE(acc), "reconcile-info/last-date", &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {"reconcile-info", "last-date"});
     if (G_VALUE_HOLDS_INT64 (&v))
         date = g_value_get_int64 (&v);
 
@@ -4337,7 +4319,7 @@ xaccAccountSetReconcileLastDate (Account *acc, time64 last_date)
     g_value_init (&v, G_TYPE_INT64);
     g_value_set_int64 (&v, last_date);
     xaccAccountBeginEdit (acc);
-    qof_instance_set_kvp (QOF_INSTANCE (acc), "/reconcile-info/last-date", &v);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {"reconcile-info", "last-date"});
     mark_account (acc);
     xaccAccountCommitEdit (acc);
 }
@@ -4354,10 +4336,10 @@ xaccAccountGetReconcileLastInterval (const Account *acc,
 
     if (!acc) return FALSE;
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
-    qof_instance_get_kvp (QOF_INSTANCE(acc),
-                          "reconcile-info/last-interval/months", &v1);
-    qof_instance_get_kvp (QOF_INSTANCE(acc),
-                          "reconcile-info/last-interval/days", &v2);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v1,
+            {"reconcile-info", "last-interval", "months"});
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v2,
+            {"reconcile-info", "last-interval", "days"});
     if (G_VALUE_HOLDS_INT64 (&v1))
         m = g_value_get_int64 (&v1);
     if (G_VALUE_HOLDS_INT64 (&v2))
@@ -4387,10 +4369,10 @@ xaccAccountSetReconcileLastInterval (Account *acc, int months, int days)
     g_value_init (&v2, G_TYPE_INT64);
     g_value_set_int64 (&v2, days);
     xaccAccountBeginEdit (acc);
-    qof_instance_set_kvp (QOF_INSTANCE (acc),
-                          "reconcile-info/last-interval/months", &v1);
-    qof_instance_set_kvp (QOF_INSTANCE (acc),
-                          "reconcile-info/last-interval/days", &v2);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v1,
+            {"reconcile-info", "last-interval", "months"});
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v2,
+            {"reconcile-info", "last-interval", "days"});
     mark_account (acc);
     xaccAccountCommitEdit (acc);
 }
@@ -4404,8 +4386,8 @@ xaccAccountGetReconcilePostponeDate (const Account *acc, time64 *postpone_date)
     gint64 date = 0;
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
-    qof_instance_get_kvp (QOF_INSTANCE(acc),
-                          "reconcile-info/postpone/date", &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v,
+            {"reconcile-info", "postpone", "date"});
     if (G_VALUE_HOLDS_INT64 (&v))
         date = g_value_get_int64 (&v);
 
@@ -4430,8 +4412,8 @@ xaccAccountSetReconcilePostponeDate (Account *acc, time64 postpone_date)
     g_value_init (&v, G_TYPE_INT64);
     g_value_set_int64 (&v, postpone_date);
     xaccAccountBeginEdit (acc);
-    qof_instance_set_kvp (QOF_INSTANCE (acc),
-                          "/reconcile-info/postpone/date", &v);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v,
+            {"reconcile-info", "postpone", "date"});
     mark_account (acc);
     xaccAccountCommitEdit (acc);
 }
@@ -4446,8 +4428,8 @@ xaccAccountGetReconcilePostponeBalance (const Account *acc,
     gnc_numeric bal = gnc_numeric_zero ();
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
-    qof_instance_get_kvp (QOF_INSTANCE(acc),
-                          "reconcile-info/postpone/balance", &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v,
+            {"reconcile-info", "postpone", "balance"});
     if (!G_VALUE_HOLDS_INT64 (&v))
         return FALSE;
 
@@ -4473,8 +4455,8 @@ xaccAccountSetReconcilePostponeBalance (Account *acc, gnc_numeric balance)
     g_value_init (&v, GNC_TYPE_NUMERIC);
     g_value_set_boxed (&v, &balance);
     xaccAccountBeginEdit (acc);
-    qof_instance_set_kvp (QOF_INSTANCE (acc),
-                          "/reconcile-info/postpone/balance", &v);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v,
+            {"reconcile-info", "postpone", "balance"});
     mark_account (acc);
     xaccAccountCommitEdit (acc);
 }
@@ -4489,7 +4471,7 @@ xaccAccountClearReconcilePostpone (Account *acc)
     if (!acc) return;
 
     xaccAccountBeginEdit (acc);
-    qof_instance_set_kvp (QOF_INSTANCE(acc), "reconcile-info/postpone", NULL);
+    qof_instance_set_path_kvp (QOF_INSTANCE(acc), nullptr, {"reconcile-info", "postpone"});
     mark_account (acc);
     xaccAccountCommitEdit (acc);
 }
@@ -4504,7 +4486,7 @@ xaccAccountClearReconcilePostpone (Account *acc)
 gboolean
 xaccAccountGetAutoInterestXfer (const Account *acc, gboolean default_value)
 {
-    return boolean_from_key (acc, "reconcile-info/auto-interest-transfer");
+    return boolean_from_key (acc, {"reconcile-info", "auto-interest-transfer"});
 }
 
 /********************************************************************\
@@ -4513,7 +4495,7 @@ xaccAccountGetAutoInterestXfer (const Account *acc, gboolean default_value)
 void
 xaccAccountSetAutoInterestXfer (Account *acc, gboolean option)
 {
-    set_boolean_key (acc, "reconcile-info/auto-interest-transfer", option);
+    set_boolean_key (acc, {"reconcile-info", "auto-interest-transfer"}, option);
 }
 
 /********************************************************************\
@@ -4524,7 +4506,7 @@ xaccAccountGetLastNum (const Account *acc)
 {
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(GNC_IS_ACCOUNT(acc), FALSE);
-    qof_instance_get_kvp (QOF_INSTANCE(acc), "last-num", &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {"last-num"});
     return G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
 }
 
@@ -4540,7 +4522,7 @@ xaccAccountSetLastNum (Account *acc, const char *num)
 
     g_value_set_string (&v, num);
     xaccAccountBeginEdit (acc);
-    qof_instance_set_kvp (QOF_INSTANCE (acc), "last-num", &v);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {"last-num"});
     mark_account (acc);
     xaccAccountCommitEdit (acc);
 }
@@ -4594,13 +4576,13 @@ Account *
 xaccAccountGainsAccount (Account *acc, gnc_commodity *curr)
 {
     GValue v = G_VALUE_INIT;
-    gchar *curr_name = g_strdup_printf ("/lot-mgmt/gains-act/%s",
-                                      gnc_commodity_get_unique_name (curr));
+    std::vector<std::string> path {"lot-mgmt", "gains-acct",
+        gnc_commodity_get_unique_name (curr)};
     GncGUID *guid = NULL;
     Account *gains_account;
 
     g_return_val_if_fail (acc != NULL, NULL);
-    qof_instance_get_kvp (QOF_INSTANCE(acc), curr_name, &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, path);
     if (G_VALUE_HOLDS_BOXED (&v))
         guid = (GncGUID*)g_value_get_boxed (&v);
     if (guid == NULL) /* No gains account for this currency */
@@ -4613,7 +4595,7 @@ xaccAccountGainsAccount (Account *acc, gnc_commodity *curr)
              GValue vr = G_VALUE_INIT;
              g_value_init (&vr, GNC_TYPE_GUID);
              g_value_set_boxed (&vr, guid);
-             qof_instance_set_kvp (QOF_INSTANCE (acc), curr_name, &vr);
+             qof_instance_set_path_kvp (QOF_INSTANCE (acc), &vr, path);
              qof_instance_set_dirty (QOF_INSTANCE (acc));
         }
         xaccAccountCommitEdit (acc);
@@ -4622,7 +4604,6 @@ xaccAccountGainsAccount (Account *acc, gnc_commodity *curr)
         gains_account = xaccAccountLookup (guid,
                                            qof_instance_get_book(acc));
 
-    g_free (curr_name);
     return gains_account;
 }
 
@@ -4642,11 +4623,10 @@ dxaccAccountSetPriceSrc(Account *acc, const char *src)
             GValue v = G_VALUE_INIT;
             g_value_init (&v, G_TYPE_STRING);
             g_value_set_string (&v, src);
-            qof_instance_set_kvp (QOF_INSTANCE(acc),
-                                  "old-price-source", &v);
+            qof_instance_set_path_kvp (QOF_INSTANCE(acc), &v, {"old-price-source"});
         }
         else
-            qof_instance_set_kvp (QOF_INSTANCE(acc), "old-price-source", NULL);
+            qof_instance_set_path_kvp (QOF_INSTANCE(acc), nullptr, {"old-price-source"});
 
         mark_account (acc);
         xaccAccountCommitEdit(acc);
@@ -4664,7 +4644,7 @@ dxaccAccountGetPriceSrc(const Account *acc)
 
     if (!xaccAccountIsPriced(acc)) return NULL;
 
-    qof_instance_get_kvp (QOF_INSTANCE(acc), "old-price-source", &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE(acc), &v, {"old-price-source"});
     return G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
 }
 
@@ -4680,7 +4660,7 @@ dxaccAccountSetQuoteTZ(Account *acc, const char *tz)
     xaccAccountBeginEdit(acc);
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, tz);
-    qof_instance_set_kvp (QOF_INSTANCE (acc), "old-quote-tz", &v);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v, {"old-quote-tz"});
     mark_account (acc);
     xaccAccountCommitEdit(acc);
 }
@@ -4694,7 +4674,7 @@ dxaccAccountGetQuoteTZ(const Account *acc)
     GValue v = G_VALUE_INIT;
     if (!acc) return NULL;
     if (!xaccAccountIsPriced(acc)) return NULL;
-    qof_instance_get_kvp (QOF_INSTANCE (acc), "old-quote-tz", &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE (acc), &v, {"old-quote-tz"});
     return G_VALUE_HOLDS_STRING (&v) ? g_value_get_string (&v) : NULL;
 }
 
@@ -4714,8 +4694,8 @@ xaccAccountSetReconcileChildrenStatus(Account *acc, gboolean status)
      */
     g_value_init (&v, G_TYPE_INT64);
     g_value_set_int64 (&v, status);
-    qof_instance_set_kvp (QOF_INSTANCE (acc),
-                          "/reconcile-info/include-children", &v);
+    qof_instance_set_path_kvp (QOF_INSTANCE (acc), &v,
+            {"reconcile-info", "include-children"});
     mark_account(acc);
     xaccAccountCommitEdit (acc);
 }
@@ -4732,8 +4712,8 @@ xaccAccountGetReconcileChildrenStatus(const Account *acc)
      */
     GValue v = G_VALUE_INIT;
     if (!acc) return FALSE;
-    qof_instance_get_kvp (QOF_INSTANCE (acc),
-                          "reconcile-info/include-children", &v);
+    qof_instance_get_path_kvp (QOF_INSTANCE (acc), &v,
+            {"reconcile-info", "include-children"});
     return G_VALUE_HOLDS_INT64 (&v) ? g_value_get_int64 (&v) : FALSE;
 }
 
@@ -5107,17 +5087,14 @@ gnc_account_imap_find_account (GncImportMatchMap *imap,
 {
     GValue v = G_VALUE_INIT;
     GncGUID * guid = NULL;
-    char *kvp_path;
-
     if (!imap || !key) return NULL;
-    if (!category)
-        kvp_path = g_strdup_printf (IMAP_FRAME "/%s", key);
-    else
-        kvp_path = g_strdup_printf (IMAP_FRAME "/%s/%s", category, key);
-    qof_instance_get_kvp (QOF_INSTANCE (imap->acc), kvp_path, &v);
+    std::vector<std::string> path {IMAP_FRAME};
+    if (category)
+        path.push_back (category);
+    path.push_back (key);
+    qof_instance_get_path_kvp (QOF_INSTANCE (imap->acc), &v, path);
     if (G_VALUE_HOLDS_BOXED (&v))
         guid = (GncGUID*)g_value_get_boxed (&v);
-    g_free (kvp_path);
     return xaccAccountLookup (guid, imap->book);
 }
 
@@ -5129,19 +5106,15 @@ gnc_account_imap_add_account (GncImportMatchMap *imap,
                               Account *acc)
 {
     GValue v = G_VALUE_INIT;
-    char *kvp_path;
-
     if (!imap || !key || !acc || (strlen (key) == 0)) return;
-    if (!category)
-        kvp_path = g_strdup_printf (IMAP_FRAME "/%s", key);
-    else
-        kvp_path = g_strdup_printf (IMAP_FRAME "/%s/%s", category, key);
-
+    std::vector<std::string> path {IMAP_FRAME};
+    if (category)
+        path.emplace_back (category);
+    path.emplace_back (key);
     g_value_init (&v, GNC_TYPE_GUID);
     g_value_set_boxed (&v, xaccAccountGetGUID (acc));
     xaccAccountBeginEdit (imap->acc);
-    qof_instance_set_kvp (QOF_INSTANCE (imap->acc), kvp_path, &v);
-    g_free (kvp_path);
+    qof_instance_set_path_kvp (QOF_INSTANCE (imap->acc), &v, path);
     qof_instance_set_dirty (QOF_INSTANCE (imap->acc));
     xaccAccountCommitEdit (imap->acc);
 }
@@ -5152,28 +5125,18 @@ gnc_account_imap_delete_account (GncImportMatchMap *imap,
                                  const char *category,
                                  const char *key)
 {
-    char *kvp_path;
-
     if (!imap || !key) return;
-    if (!category)
-        kvp_path = g_strdup_printf (IMAP_FRAME "/%s", key);
-    else
-        kvp_path = g_strdup_printf (IMAP_FRAME "/%s/%s", category, key);
-
+    std::vector<std::string> path {IMAP_FRAME};
+    if (category)
+        path.emplace_back (category);
+    path.emplace_back (key);
     xaccAccountBeginEdit (imap->acc);
-
-    if (qof_instance_has_slot (QOF_INSTANCE (imap->acc), kvp_path))
+    if (qof_instance_has_path_slot (QOF_INSTANCE (imap->acc), path))
     {
-        qof_instance_slot_delete (QOF_INSTANCE (imap->acc), kvp_path);
-        g_free (kvp_path);
-
+        qof_instance_slot_path_delete (QOF_INSTANCE (imap->acc), path);
         if (category)
-        {
-            kvp_path = g_strdup_printf (IMAP_FRAME "/%s", category);
-            qof_instance_slot_delete_if_empty (QOF_INSTANCE (imap->acc), kvp_path);
-            g_free (kvp_path);
-        }
-        qof_instance_slot_delete_if_empty (QOF_INSTANCE (imap->acc), IMAP_FRAME);
+            qof_instance_slot_path_delete_if_empty (QOF_INSTANCE (imap->acc), {IMAP_FRAME, category});
+        qof_instance_slot_path_delete_if_empty (QOF_INSTANCE (imap->acc), {IMAP_FRAME});
     }
     qof_instance_set_dirty (QOF_INSTANCE (imap->acc));
     xaccAccountCommitEdit (imap->acc);
@@ -5333,20 +5296,20 @@ gnc_account_imap_find_account_bayes (GncImportMatchMap *imap, GList *tokens)
 }
 
 static void
-change_imap_entry (GncImportMatchMap *imap, gchar const * kvp_path, int64_t token_count)
+change_imap_entry (GncImportMatchMap *imap, std::string const & path, int64_t token_count)
 {
     GValue value = G_VALUE_INIT;
 
-    PINFO("Source Account is '%s', kvp_path is '%s', Count is '%" G_GINT64_FORMAT "'",
-           xaccAccountGetName (imap->acc), kvp_path, token_count);
+    PINFO("Source Account is '%s', Count is '%" G_GINT64_FORMAT "'",
+           xaccAccountGetName (imap->acc), token_count);
 
     // check for existing guid entry
-    if (qof_instance_has_slot (QOF_INSTANCE(imap->acc), kvp_path))
+    if (qof_instance_has_slot (QOF_INSTANCE(imap->acc), path.c_str ()))
     {
         int64_t  existing_token_count = 0;
 
         // get the existing_token_count value
-        qof_instance_get_kvp (QOF_INSTANCE (imap->acc), kvp_path, &value);
+        qof_instance_get_path_kvp (QOF_INSTANCE (imap->acc), &value, {path});
 
         if (G_VALUE_HOLDS_INT64 (&value))
             existing_token_count = g_value_get_int64 (&value);
@@ -5362,7 +5325,7 @@ change_imap_entry (GncImportMatchMap *imap, gchar const * kvp_path, int64_t toke
     g_value_set_int64 (&value, token_count);
 
     // Add or Update the entry based on guid
-    qof_instance_set_kvp (QOF_INSTANCE (imap->acc), kvp_path, &value);
+    qof_instance_set_path_kvp (QOF_INSTANCE (imap->acc), &value, {path});
 
     /* Set a feature flag in the book for the change to use guid.
      * This will prevent older GnuCash versions that don't support this feature
@@ -5410,11 +5373,11 @@ gnc_account_imap_add_account_bayes (GncImportMatchMap *imap,
         /* start off with one token for this account */
         token_count = 1;
         PINFO("adding token '%s'", (char*)current_token->data);
-        std::string translated_token {static_cast <char*> (current_token->data)};
-        std::replace (translated_token.begin (), translated_token.end (), '/', '-');
+        std::string translated_token {static_cast<char*>(current_token->data)};
+        std::replace(translated_token.begin(), translated_token.end(), '/', '-');
         auto path = std::string {IMAP_FRAME_BAYES} + '-' + translated_token + '-' + guid_string;
         /* change the imap entry for the account */
-        change_imap_entry (imap, path.c_str (), token_count);
+        change_imap_entry (imap, path, token_count);
     }
     /* free up the account fullname and guid string */
     qof_instance_set_dirty (QOF_INSTANCE (imap->acc));
@@ -5566,12 +5529,10 @@ gnc_account_get_map_entry (Account *acc, const char *full_category)
 {
     GValue v = G_VALUE_INIT;
     gchar *text = NULL;
-    gchar *kvp_path = g_strdup (full_category);
-
-    if (qof_instance_has_slot (QOF_INSTANCE(acc), kvp_path))
+    std::vector<std::string> path {full_category};
+    if (qof_instance_has_path_slot (QOF_INSTANCE (acc), path))
     {
-        qof_instance_get_kvp (QOF_INSTANCE(acc), kvp_path, &v);
-
+        qof_instance_get_path_kvp (QOF_INSTANCE (acc), &v, path);
         if (G_VALUE_HOLDS_STRING (&v))
         {
             gchar const *string;
@@ -5579,7 +5540,6 @@ gnc_account_get_map_entry (Account *acc, const char *full_category)
             text = g_strdup (string);
         }
     }
-    g_free (kvp_path);
     return text;
 }
 
@@ -5729,7 +5689,7 @@ static bool
 run_once_key_set (char const * key, QofBook * book)
 {
     GValue value G_VALUE_INIT;
-    qof_instance_get_kvp (QOF_INSTANCE(book), key, &value);
+    qof_instance_get_path_kvp (QOF_INSTANCE(book), &value, {key});
     return G_VALUE_HOLDS_STRING(&value) && strcmp(g_value_get_string(&value), "true");
 }
 
@@ -5739,7 +5699,7 @@ set_run_once_key (char const * key, QofBook * book)
     GValue value G_VALUE_INIT;
     g_value_init(&value, G_TYPE_BOOLEAN);
     g_value_set_boolean(&value, TRUE);
-    qof_instance_set_kvp(QOF_INSTANCE (book), key, &value);
+    qof_instance_set_path_kvp(QOF_INSTANCE (book), &value, {key});
 }
 
 void
diff --git a/libgnucash/engine/Scrub.c b/libgnucash/engine/Scrub.c
index d27752e..a036fff 100644
--- a/libgnucash/engine/Scrub.c
+++ b/libgnucash/engine/Scrub.c
@@ -1228,10 +1228,10 @@ xaccAccountDeleteOldData (Account *account)
 {
     if (!account) return;
     xaccAccountBeginEdit (account);
-    qof_instance_set_kvp (QOF_INSTANCE (account), "old-currency", NULL);
-    qof_instance_set_kvp (QOF_INSTANCE (account), "old-security", NULL);
-    qof_instance_set_kvp (QOF_INSTANCE (account), "old-currency-scu", NULL);
-    qof_instance_set_kvp (QOF_INSTANCE (account), "old-security-scu", NULL);
+    qof_instance_set_var_kvp (QOF_INSTANCE (account), NULL, 1, "old-currency");
+    qof_instance_set_var_kvp (QOF_INSTANCE (account), NULL, 1, "old-security");
+    qof_instance_set_var_kvp (QOF_INSTANCE (account), NULL, 1, "old-currency-scu");
+    qof_instance_set_var_kvp (QOF_INSTANCE (account), NULL, 1, "old-security-scu");
     qof_instance_set_dirty (QOF_INSTANCE (account));
     xaccAccountCommitEdit (account);
 }
@@ -1337,22 +1337,22 @@ xaccAccountScrubKvp (Account *account)
 
     if (!account) return;
 
-    qof_instance_get_kvp (QOF_INSTANCE (account), "notes", &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (account), &v, 1, "notes");
     if (G_VALUE_HOLDS_STRING (&v))
     {
         str2 = g_strstrip(g_value_dup_string(&v));
         if (strlen(str2) == 0)
-            qof_instance_slot_delete (QOF_INSTANCE (account), "notes");
+            qof_instance_slot_var_delete (QOF_INSTANCE (account), 1, "notes");
         g_free(str2);
     }
 
-    qof_instance_get_kvp (QOF_INSTANCE (account), "placeholder", &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (account), &v, 1, "placeholder");
     if ((G_VALUE_HOLDS_STRING (&v) &&
         strcmp(g_value_get_string (&v), "false") == 0) ||
         (G_VALUE_HOLDS_BOOLEAN (&v) && ! g_value_get_boolean (&v)))
-        qof_instance_slot_delete (QOF_INSTANCE (account), "placeholder");
+        qof_instance_slot_var_delete (QOF_INSTANCE (account), 1, "placeholder");
 
-    qof_instance_slot_delete_if_empty (QOF_INSTANCE (account), "hbci");
+    qof_instance_slot_var_delete_if_empty (QOF_INSTANCE (account), 1, "hbci");
 }
 
 /* ================================================================ */
diff --git a/libgnucash/engine/Split.c b/libgnucash/engine/Split.c
index 86072d1..772849f 100644
--- a/libgnucash/engine/Split.c
+++ b/libgnucash/engine/Split.c
@@ -184,40 +184,31 @@ gnc_split_get_property(GObject         *object,
             g_value_take_object(value, split->lot);
             break;
         case PROP_SX_CREDIT_FORMULA:
-            key = GNC_SX_ID "/" GNC_SX_CREDIT_FORMULA;
-            qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_FORMULA);
             break;
         case PROP_SX_CREDIT_NUMERIC:
-            key = GNC_SX_ID "/" GNC_SX_CREDIT_NUMERIC;
-            qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_NUMERIC);
             break;
         case PROP_SX_DEBIT_FORMULA:
-            key = GNC_SX_ID "/" GNC_SX_DEBIT_FORMULA;
-            qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_FORMULA);
             break;
         case PROP_SX_DEBIT_NUMERIC:
-            key = GNC_SX_ID "/" GNC_SX_DEBIT_NUMERIC;
-            qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_NUMERIC);
             break;
         case PROP_SX_ACCOUNT:
-            key = GNC_SX_ID "/" GNC_SX_ACCOUNT;
-            qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_ACCOUNT);
             break;
         case PROP_SX_SHARES:
-            key = GNC_SX_ID "/" GNC_SX_SHARES;
-            qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_SHARES);
             break;
         case PROP_ONLINE_ACCOUNT:
-            key = "online_id";
-            qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 1, "online_id");
             break;
         case PROP_GAINS_SPLIT:
-            key = "gains-split";
-            qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 1, "gains-split");
             break;
         case PROP_GAINS_SOURCE:
-            key = "gains-source";
-            qof_instance_get_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_get_var_kvp (QOF_INSTANCE (split), value, 1, "gains-source");
             break;
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -270,40 +261,31 @@ gnc_split_set_property(GObject         *object,
             xaccSplitSetLot(split, g_value_get_object(value));
             break;
         case PROP_SX_CREDIT_FORMULA:
-            key = GNC_SX_ID "/" GNC_SX_CREDIT_FORMULA;
-            qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_FORMULA);
             break;
         case PROP_SX_CREDIT_NUMERIC:
-            key = GNC_SX_ID "/" GNC_SX_CREDIT_NUMERIC;
-            qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_CREDIT_NUMERIC);
             break;
         case PROP_SX_DEBIT_FORMULA:
-            key = GNC_SX_ID "/" GNC_SX_DEBIT_FORMULA;
-            qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_FORMULA);
             break;
         case PROP_SX_DEBIT_NUMERIC:
-            key = GNC_SX_ID "/" GNC_SX_DEBIT_NUMERIC;
-            qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_DEBIT_NUMERIC);
             break;
         case PROP_SX_ACCOUNT:
-            key = GNC_SX_ID "/" GNC_SX_ACCOUNT;
-            qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_ACCOUNT);
             break;
         case PROP_SX_SHARES:
-            key = GNC_SX_ID "/" GNC_SX_SHARES;
-            qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 2, GNC_SX_ID, GNC_SX_SHARES);
             break;
         case PROP_ONLINE_ACCOUNT:
-            key = "online_id";
-            qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 1, "online_id");
             break;
         case PROP_GAINS_SPLIT:
-            key = "gains-split";
-            qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 1, "gains-split");
             break;
         case PROP_GAINS_SOURCE:
-            key = "gains-source";
-            qof_instance_set_kvp (QOF_INSTANCE (split), key, value);
+            qof_instance_set_var_kvp (QOF_INSTANCE (split), value, 1, "gains-source");
             break;
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -1097,7 +1079,7 @@ xaccSplitDetermineGainStatus (Split *split)
         return;
     }
 
-    qof_instance_get_kvp (QOF_INSTANCE (split), "gains-source", &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (split), &v, 1, "gains-source");
     if (G_VALUE_HOLDS_BOXED (&v))
         guid = (GncGUID*)g_value_get_boxed (&v);
     if (!guid)
@@ -1990,7 +1972,7 @@ xaccSplitGetType(const Split *s)
     const char *split_type = NULL;
 
     if (!s) return NULL;
-    qof_instance_get_kvp (QOF_INSTANCE (s), "split-type", &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
     if (G_VALUE_HOLDS_STRING (&v))
         split_type = g_value_get_string (&v);
     return split_type ? split_type : "normal";
@@ -2007,7 +1989,7 @@ xaccSplitMakeStockSplit(Split *s)
     s->value = gnc_numeric_zero();
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, "stock-split");
-    qof_instance_set_kvp (QOF_INSTANCE (s), "split-type", &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (s), &v, 1, "split-type");
     SET_GAINS_VDIRTY(s);
     mark_split(s);
     qof_instance_set_dirty(QOF_INSTANCE(s));
@@ -2144,7 +2126,7 @@ xaccSplitVoidFormerAmount(const Split *split)
     GValue v = G_VALUE_INIT;
     gnc_numeric *num = NULL;
     g_return_val_if_fail(split, gnc_numeric_zero());
-    qof_instance_get_kvp (QOF_INSTANCE (split), void_former_amt_str, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (split), &v, 1, void_former_amt_str);
     if (G_VALUE_HOLDS_BOXED (&v))
         num = (gnc_numeric*)g_value_get_boxed (&v);
     return num ? *num : gnc_numeric_zero();
@@ -2156,7 +2138,7 @@ xaccSplitVoidFormerValue(const Split *split)
     GValue v = G_VALUE_INIT;
     gnc_numeric *num = NULL;
     g_return_val_if_fail(split, gnc_numeric_zero());
-    qof_instance_get_kvp (QOF_INSTANCE (split), void_former_val_str, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (split), &v, 1, void_former_val_str);
     if (G_VALUE_HOLDS_BOXED (&v))
         num = (gnc_numeric*)g_value_get_boxed (&v);
     return num ? *num : gnc_numeric_zero();
@@ -2171,10 +2153,10 @@ xaccSplitVoid(Split *split)
     g_value_init (&v, GNC_TYPE_NUMERIC);
     num =  xaccSplitGetAmount(split);
     g_value_set_boxed (&v, &num);
-    qof_instance_set_kvp (QOF_INSTANCE (split), void_former_amt_str, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (split), &v, 1, void_former_amt_str);
     num =  xaccSplitGetValue(split);
     g_value_set_boxed (&v, &num);
-    qof_instance_set_kvp (QOF_INSTANCE (split), void_former_val_str, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (split), &v, 1, void_former_val_str);
 
     /* Marking dirty handled by SetAmount etc. */
     xaccSplitSetAmount (split, zero);
@@ -2188,8 +2170,8 @@ xaccSplitUnvoid(Split *split)
     xaccSplitSetAmount (split, xaccSplitVoidFormerAmount(split));
     xaccSplitSetValue (split, xaccSplitVoidFormerValue(split));
     xaccSplitSetReconcile(split, NREC);
-    qof_instance_set_kvp (QOF_INSTANCE (split), void_former_amt_str, NULL);
-    qof_instance_set_kvp (QOF_INSTANCE (split), void_former_val_str, NULL);
+    qof_instance_set_var_kvp (QOF_INSTANCE (split), NULL, 1, void_former_amt_str);
+    qof_instance_set_var_kvp (QOF_INSTANCE (split), NULL, 1, void_former_val_str);
     qof_instance_set_dirty (QOF_INSTANCE (split));
 }
 
diff --git a/libgnucash/engine/Transaction.c b/libgnucash/engine/Transaction.c
index 811100d..cfa651a 100644
--- a/libgnucash/engine/Transaction.c
+++ b/libgnucash/engine/Transaction.c
@@ -338,17 +338,14 @@ gnc_transaction_get_property(GObject* object,
         g_value_set_boxed(value, &tx->date_entered);
         break;
     case PROP_INVOICE:
-	key = GNC_INVOICE_ID "/" GNC_INVOICE_GUID;
-	qof_instance_get_kvp (QOF_INSTANCE (tx), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (tx), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
+        break;
     case PROP_SX_TXN:
-	key = GNC_SX_FROM;
-	qof_instance_get_kvp (QOF_INSTANCE (tx), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (tx), value, 1, GNC_SX_FROM);
+        break;
     case PROP_ONLINE_ACCOUNT:
-	key = "online_id";
-	qof_instance_get_kvp (QOF_INSTANCE (tx), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (tx), value, 1, "online_id");
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -387,17 +384,14 @@ gnc_transaction_set_property(GObject* object,
         xaccTransSetDateEnteredTS(tx, g_value_get_boxed(value));
         break;
     case PROP_INVOICE:
-	key = GNC_INVOICE_ID "/" GNC_INVOICE_GUID;
-	qof_instance_set_kvp (QOF_INSTANCE (tx), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (tx), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
+        break;
     case PROP_SX_TXN:
-	key = GNC_SX_FROM;
-	qof_instance_set_kvp (QOF_INSTANCE (tx), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (tx), value, 1, GNC_SX_FROM);
+        break;
     case PROP_ONLINE_ACCOUNT:
-	key = "online_id";
-	qof_instance_set_kvp (QOF_INSTANCE (tx), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (tx), value, 1, "online_id");
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -1993,7 +1987,7 @@ xaccTransSetDatePostedGDate (Transaction *trans, GDate date)
      * clearly be distinguished from the Timespec. */
     g_value_init (&v, G_TYPE_DATE);
     g_value_set_boxed (&v, &date);
-    qof_instance_set_kvp (QOF_INSTANCE(trans), TRANS_DATE_POSTED, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_DATE_POSTED);
     /* mark dirty and commit handled by SetDateInternal */
     xaccTransSetDateInternal(trans, &trans->date_posted,
                              gdate_to_timespec(date));
@@ -2069,7 +2063,7 @@ xaccTransSetDateDueTS (Transaction *trans, const Timespec *ts)
     g_value_init (&v, GNC_TYPE_TIMESPEC);
     g_value_set_boxed (&v, ts);
     xaccTransBeginEdit(trans);
-    qof_instance_set_kvp (QOF_INSTANCE (trans), TRANS_DATE_DUE_KVP, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_DUE_KVP);
     qof_instance_set_dirty(QOF_INSTANCE(trans));
     xaccTransCommitEdit(trans);
 }
@@ -2083,7 +2077,7 @@ xaccTransSetTxnType (Transaction *trans, char type)
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, s);
     xaccTransBeginEdit(trans);
-    qof_instance_set_kvp (QOF_INSTANCE (trans), TRANS_TXN_TYPE_KVP, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_TXN_TYPE_KVP);
     qof_instance_set_dirty(QOF_INSTANCE(trans));
     xaccTransCommitEdit(trans);
 }
@@ -2093,8 +2087,7 @@ void xaccTransClearReadOnly (Transaction *trans)
     if (trans)
     {
         xaccTransBeginEdit(trans);
-	qof_instance_set_kvp (QOF_INSTANCE (trans),
-			      TRANS_READ_ONLY_REASON, NULL);
+        qof_instance_set_var_kvp (QOF_INSTANCE (trans), NULL, 1, TRANS_READ_ONLY_REASON);
         qof_instance_set_dirty(QOF_INSTANCE(trans));
         xaccTransCommitEdit(trans);
     }
@@ -2105,11 +2098,11 @@ xaccTransSetReadOnly (Transaction *trans, const char *reason)
 {
     if (trans && reason)
     {
-	GValue v = G_VALUE_INIT;
-	g_value_init (&v, G_TYPE_STRING);
-	g_value_set_string (&v, reason);
+        GValue v = G_VALUE_INIT;
+        g_value_init (&v, G_TYPE_STRING);
+        g_value_set_string (&v, reason);
         xaccTransBeginEdit(trans);
-	qof_instance_set_kvp (QOF_INSTANCE (trans), TRANS_READ_ONLY_REASON, &v);
+        qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_READ_ONLY_REASON);
         qof_instance_set_dirty(QOF_INSTANCE(trans));
         xaccTransCommitEdit(trans);
     }
@@ -2167,7 +2160,7 @@ xaccTransSetAssociation (Transaction *trans, const char *assoc)
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, assoc);
     xaccTransBeginEdit(trans);
-    qof_instance_set_kvp (QOF_INSTANCE (trans), assoc_uri_str, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, assoc_uri_str);
     qof_instance_set_dirty(QOF_INSTANCE(trans));
     xaccTransCommitEdit(trans);
 }
@@ -2189,7 +2182,7 @@ xaccTransSetNotes (Transaction *trans, const char *notes)
     g_value_set_string (&v, notes);
     xaccTransBeginEdit(trans);
 
-    qof_instance_set_kvp (QOF_INSTANCE (trans), trans_notes_str, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
     qof_instance_set_dirty(QOF_INSTANCE(trans));
     xaccTransCommitEdit(trans);
 }
@@ -2202,13 +2195,13 @@ xaccTransSetIsClosingTxn (Transaction *trans, gboolean is_closing)
 
     if (is_closing)
     {
-	GValue v = G_VALUE_INIT;
-	g_value_init (&v, G_TYPE_INT64);
-	g_value_set_int64 (&v, 1);
-        qof_instance_set_kvp (QOF_INSTANCE (trans), trans_is_closing_str, &v);
+        GValue v = G_VALUE_INIT;
+        g_value_init (&v, G_TYPE_INT64);
+        g_value_set_int64 (&v, 1);
+        qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_is_closing_str);
     }
     else
-	qof_instance_set_kvp (QOF_INSTANCE (trans), trans_is_closing_str, NULL);
+        qof_instance_set_var_kvp (QOF_INSTANCE (trans), NULL, 1, trans_is_closing_str);
     qof_instance_set_dirty(QOF_INSTANCE(trans));
     xaccTransCommitEdit(trans);
 }
@@ -2343,7 +2336,7 @@ xaccTransGetAssociation (const Transaction *trans)
 {
     GValue v = G_VALUE_INIT;
     if (!trans) return NULL;
-    qof_instance_get_kvp (QOF_INSTANCE (trans), assoc_uri_str, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, assoc_uri_str);
     if (G_VALUE_HOLDS_STRING (&v))
          return g_value_get_string (&v);
     return NULL;
@@ -2354,7 +2347,7 @@ xaccTransGetNotes (const Transaction *trans)
 {
     GValue v = G_VALUE_INIT;
     if (!trans) return NULL;
-    qof_instance_get_kvp (QOF_INSTANCE (trans), trans_notes_str, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
     if (G_VALUE_HOLDS_STRING (&v))
          return g_value_get_string (&v);
     return NULL;
@@ -2365,7 +2358,7 @@ xaccTransGetIsClosingTxn (const Transaction *trans)
 {
     GValue v = G_VALUE_INIT;
     if (!trans) return FALSE;
-    qof_instance_get_kvp (QOF_INSTANCE (trans), trans_is_closing_str, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_is_closing_str);
     if (G_VALUE_HOLDS_INT64 (&v))
          return g_value_get_int64 (&v);
     return FALSE;
@@ -2419,11 +2412,11 @@ xaccTransGetDatePostedGDate (const Transaction *trans)
         /* Can we look up this value in the kvp slot? If yes, use it
          * from there because it doesn't suffer from time zone
          * shifts. */
-	GValue v = G_VALUE_INIT;
-	qof_instance_get_kvp (QOF_INSTANCE (trans), TRANS_DATE_POSTED, &v);
+        GValue v = G_VALUE_INIT;
+        qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_POSTED);
         if (G_VALUE_HOLDS_BOXED (&v))
              result = *(GDate*)g_value_get_boxed (&v);
-	if (! g_date_valid (&result))
+        if (! g_date_valid (&result))
         {
              /* Well, this txn doesn't have a GDate saved in a
               * slot. Avoid getting the date in the local TZ by
@@ -2455,7 +2448,7 @@ xaccTransGetDateDueTS (const Transaction *trans, Timespec *ts)
     GValue v = G_VALUE_INIT;
     if (!trans || !ts) return;
 
-    qof_instance_get_kvp (QOF_INSTANCE (trans), TRANS_DATE_DUE_KVP, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_DATE_DUE_KVP);
     if (G_VALUE_HOLDS_BOXED (&v))
          *ts = *(Timespec*)g_value_get_boxed (&v);
     if (ts->tv_sec == 0)
@@ -2477,11 +2470,11 @@ xaccTransGetTxnType (const Transaction *trans)
     GValue v = G_VALUE_INIT;
 
     if (!trans) return TXN_TYPE_NONE;
-    qof_instance_get_kvp (QOF_INSTANCE (trans), TRANS_TXN_TYPE_KVP, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, TRANS_TXN_TYPE_KVP);
     if (G_VALUE_HOLDS_STRING (&v))
          s = g_value_get_string (&v);
     if (s && strlen (s) == 1)
-	return *s;
+        return *s;
 
     return TXN_TYPE_NONE;
 }
@@ -2495,11 +2488,11 @@ xaccTransGetReadOnly (const Transaction *trans)
     GValue v = G_VALUE_INIT;
     const char *s = NULL;
     if (trans == NULL) return NULL;
-    qof_instance_get_kvp (QOF_INSTANCE(trans), TRANS_READ_ONLY_REASON, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_READ_ONLY_REASON);
     if (G_VALUE_HOLDS_STRING (&v))
          s = g_value_get_string (&v);
     if (s && strlen (s))
-	return s;
+        return s;
 
     return NULL;
 }
@@ -2693,20 +2686,20 @@ xaccTransVoid(Transaction *trans, const char *reason)
         return;
     }
     xaccTransBeginEdit(trans);
-    qof_instance_get_kvp (QOF_INSTANCE (trans), trans_notes_str, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
     if (G_VALUE_HOLDS_STRING (&v))
-        qof_instance_set_kvp (QOF_INSTANCE (trans), void_former_notes_str, &v);
+        qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, void_former_notes_str);
     else
         g_value_init (&v, G_TYPE_STRING);
 
     g_value_set_string (&v, _("Voided transaction"));
-    qof_instance_set_kvp (QOF_INSTANCE (trans), trans_notes_str, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
     g_value_set_string (&v, reason);
-    qof_instance_set_kvp (QOF_INSTANCE (trans), void_reason_str, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
 
     gnc_timespec_to_iso8601_buff (timespec_now (), iso8601_str);
     g_value_set_string (&v, iso8601_str);
-    qof_instance_set_kvp (QOF_INSTANCE (trans), void_time_str, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, void_time_str);
 
     FOR_EACH_SPLIT(trans, xaccSplitVoid(s));
 
@@ -2722,7 +2715,7 @@ xaccTransGetVoidStatus(const Transaction *trans)
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(trans, FALSE);
 
-    qof_instance_get_kvp (QOF_INSTANCE (trans), void_reason_str, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
     if (G_VALUE_HOLDS_STRING (&v))
          s = g_value_get_string (&v);
     return s && strlen(s);
@@ -2734,7 +2727,7 @@ xaccTransGetVoidReason(const Transaction *trans)
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(trans, FALSE);
 
-    qof_instance_get_kvp (QOF_INSTANCE (trans), void_reason_str, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
     if (G_VALUE_HOLDS_STRING (&v))
          return g_value_get_string (&v);
     return NULL;
@@ -2748,11 +2741,11 @@ xaccTransGetVoidTime(const Transaction *tr)
     Timespec void_time = {0, 0};
 
     g_return_val_if_fail(tr, void_time);
-    qof_instance_get_kvp (QOF_INSTANCE (tr), void_time_str, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (tr), &v, 1, void_time_str);
     if (G_VALUE_HOLDS_STRING (&v))
         s = g_value_get_string (&v);
     if (s)
-	return gnc_iso8601_to_timespec_gmt (s);
+        return gnc_iso8601_to_timespec_gmt (s);
     return void_time;
 }
 
@@ -2763,18 +2756,18 @@ xaccTransUnvoid (Transaction *trans)
     const char *s = NULL;
     g_return_if_fail(trans);
 
-    qof_instance_get_kvp (QOF_INSTANCE (trans), void_reason_str, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, void_reason_str);
     if (G_VALUE_HOLDS_STRING (&v))
         s = g_value_get_string (&v);
     if (s == NULL) return; /* Transaction isn't voided. Bail. */
     xaccTransBeginEdit(trans);
 
-    qof_instance_get_kvp (QOF_INSTANCE (trans), void_former_notes_str, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (trans), &v, 1, void_former_notes_str);
     if (G_VALUE_HOLDS_STRING (&v))
-        qof_instance_set_kvp (QOF_INSTANCE (trans), trans_notes_str, &v);
-    qof_instance_set_kvp (QOF_INSTANCE (trans), void_former_notes_str, NULL);
-    qof_instance_set_kvp (QOF_INSTANCE (trans), void_reason_str, NULL);
-    qof_instance_set_kvp (QOF_INSTANCE (trans), void_time_str, NULL);
+        qof_instance_set_var_kvp (QOF_INSTANCE (trans), &v, 1, trans_notes_str);
+    qof_instance_set_var_kvp (QOF_INSTANCE (trans), NULL, 1, void_former_notes_str);
+    qof_instance_set_var_kvp (QOF_INSTANCE (trans), NULL, 1, void_reason_str);
+    qof_instance_set_var_kvp (QOF_INSTANCE (trans), NULL, 1, void_time_str);
 
     FOR_EACH_SPLIT(trans, xaccSplitUnvoid(s));
 
@@ -2804,7 +2797,7 @@ xaccTransReverse (Transaction *orig)
     /* Now update the original with a pointer to the new one */
     g_value_init (&v, GNC_TYPE_GUID);
     g_value_set_boxed (&v, xaccTransGetGUID(trans));
-    qof_instance_set_kvp (QOF_INSTANCE (orig), TRANS_REVERSED_BY, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (orig), &v, 1, TRANS_REVERSED_BY);
 
     /* Make sure the reverse transaction is not read-only */
     xaccTransClearReadOnly(trans);
@@ -2819,7 +2812,7 @@ xaccTransGetReversedBy(const Transaction *trans)
 {
     GValue v = G_VALUE_INIT;
     g_return_val_if_fail(trans, NULL);
-    qof_instance_get_kvp (QOF_INSTANCE(trans), TRANS_REVERSED_BY, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE(trans), &v, 1, TRANS_REVERSED_BY);
     if (G_VALUE_HOLDS_BOXED (&v))
         return xaccTransLookup((GncGUID*)g_value_get_boxed (&v),
                                qof_instance_get_book(trans));
diff --git a/libgnucash/engine/gnc-budget.c b/libgnucash/engine/gnc-budget.c
index c49af4e..16c121e 100644
--- a/libgnucash/engine/gnc-budget.c
+++ b/libgnucash/engine/gnc-budget.c
@@ -473,32 +473,31 @@ gnc_budget_get_num_periods(const GncBudget* budget)
     return GET_PRIVATE(budget)->num_periods;
 }
 
-#define BUF_SIZE (10 + GUID_ENCODING_LENGTH + \
-   GNC_BUDGET_MAX_NUM_PERIODS_DIGITS)
-
 static inline void
-make_period_path (const Account *account, guint period_num, char *path)
+make_period_path (const Account *account, guint period_num, char *path1, char *path2)
 {
     const GncGUID *guid;
     gchar *bufend;
-    guid = xaccAccountGetGUID(account);
-    bufend = guid_to_string_buff(guid, path);
-    g_sprintf(bufend, "/%d", period_num);
+    guid = xaccAccountGetGUID (account);
+    guid_to_string_buff (guid, path1);
+    g_sprintf (path2, "%d", period_num);
 }
+
 /* period_num is zero-based */
 /* What happens when account is deleted, after we have an entry for it? */
 void
 gnc_budget_unset_account_period_value(GncBudget *budget, const Account *account,
                                       guint period_num)
 {
-    gchar path[BUF_SIZE];
+    gchar path_part_one [GUID_ENCODING_LENGTH];
+    gchar path_part_two [GNC_BUDGET_MAX_NUM_PERIODS_DIGITS];
 
     g_return_if_fail (budget != NULL);
     g_return_if_fail (account != NULL);
-    make_period_path (account, period_num, path);
+    make_period_path (account, period_num, path_part_one, path_part_two);
 
     gnc_budget_begin_edit(budget);
-    qof_instance_set_kvp (QOF_INSTANCE (budget), path, NULL);
+    qof_instance_set_var_kvp (QOF_INSTANCE (budget), NULL, 2, path_part_one, path_part_two);
     qof_instance_set_dirty(&budget->inst);
     gnc_budget_commit_edit(budget);
 
@@ -512,7 +511,8 @@ void
 gnc_budget_set_account_period_value(GncBudget *budget, const Account *account,
                                     guint period_num, gnc_numeric val)
 {
-    gchar path[BUF_SIZE];
+    gchar path_part_one [GUID_ENCODING_LENGTH];
+    gchar path_part_two [GNC_BUDGET_MAX_NUM_PERIODS_DIGITS];
 
     /* Watch out for an off-by-one error here:
      * period_num starts from 0 while num_periods starts from 1 */
@@ -525,17 +525,17 @@ gnc_budget_set_account_period_value(GncBudget *budget, const Account *account,
     g_return_if_fail (budget != NULL);
     g_return_if_fail (account != NULL);
 
-    make_period_path (account, period_num, path);
+    make_period_path (account, period_num, path_part_one, path_part_two);
 
     gnc_budget_begin_edit(budget);
     if (gnc_numeric_check(val))
-        qof_instance_set_kvp (QOF_INSTANCE (budget), path, NULL);
+        qof_instance_set_var_kvp (QOF_INSTANCE (budget), NULL, 2, path_part_one, path_part_two);
     else
     {
         GValue v = G_VALUE_INIT;
         g_value_init (&v, GNC_TYPE_NUMERIC);
         g_value_set_boxed (&v, &val);
-        qof_instance_set_kvp (QOF_INSTANCE (budget), path, &v);
+        qof_instance_set_var_kvp (QOF_INSTANCE (budget), &v, 2, path_part_one, path_part_two);
     }
     qof_instance_set_dirty(&budget->inst);
     gnc_budget_commit_edit(budget);
@@ -553,14 +553,15 @@ gnc_budget_is_account_period_value_set(const GncBudget *budget,
                                        guint period_num)
 {
     GValue v = G_VALUE_INIT;
-    gchar path[BUF_SIZE];
+    gchar path_part_one [GUID_ENCODING_LENGTH];
+    gchar path_part_two [GNC_BUDGET_MAX_NUM_PERIODS_DIGITS];
     gconstpointer ptr = NULL;
 
     g_return_val_if_fail(GNC_IS_BUDGET(budget), FALSE);
     g_return_val_if_fail(account, FALSE);
 
-    make_period_path (account, period_num, path);
-    qof_instance_get_kvp (QOF_INSTANCE (budget), path, &v);
+    make_period_path (account, period_num, path_part_one, path_part_two);
+    qof_instance_get_var_kvp (QOF_INSTANCE (budget), &v, 2, path_part_one, path_part_two);
     if (G_VALUE_HOLDS_BOXED (&v))
         ptr = g_value_get_boxed (&v);
     return (ptr != NULL);
@@ -572,14 +573,15 @@ gnc_budget_get_account_period_value(const GncBudget *budget,
                                     guint period_num)
 {
     gnc_numeric *numeric = NULL;
-    gchar path[BUF_SIZE];
+    gchar path_part_one [GUID_ENCODING_LENGTH];
+    gchar path_part_two [GNC_BUDGET_MAX_NUM_PERIODS_DIGITS];
     GValue v = G_VALUE_INIT;
 
     g_return_val_if_fail(GNC_IS_BUDGET(budget), gnc_numeric_zero());
     g_return_val_if_fail(account, gnc_numeric_zero());
 
-    make_period_path (account, period_num, path);
-    qof_instance_get_kvp (QOF_INSTANCE (budget), path, &v);
+    make_period_path (account, period_num, path_part_one, path_part_two);
+    qof_instance_get_var_kvp (QOF_INSTANCE (budget), &v, 2, path_part_one, path_part_two);
     if (G_VALUE_HOLDS_BOXED (&v))
         numeric = (gnc_numeric*)g_value_get_boxed (&v);
 
diff --git a/libgnucash/engine/gnc-commodity.c b/libgnucash/engine/gnc-commodity.c
index f218f8f..85570fb 100644
--- a/libgnucash/engine/gnc-commodity.c
+++ b/libgnucash/engine/gnc-commodity.c
@@ -1083,7 +1083,7 @@ gnc_commodity_get_auto_quote_control_flag(const gnc_commodity *cm)
     GValue v = G_VALUE_INIT;
 
     if (!cm) return FALSE;
-    qof_instance_get_kvp (QOF_INSTANCE (cm), "auto_quote_control", &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
     if (G_VALUE_HOLDS_STRING (&v) &&
         strcmp(g_value_get_string (&v), "false") == 0)
         return FALSE;
@@ -1145,7 +1145,7 @@ gnc_commodity_get_user_symbol(const gnc_commodity *cm)
 {
     GValue v = G_VALUE_INIT;
     if (!cm) return NULL;
-    qof_instance_get_kvp (QOF_INSTANCE(cm), "user_symbol", &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
     if (G_VALUE_HOLDS_STRING (&v))
         return g_value_get_string (&v);
     return NULL;
@@ -1316,12 +1316,12 @@ gnc_commodity_set_auto_quote_control_flag(gnc_commodity *cm,
     }
     gnc_commodity_begin_edit(cm);
     if (flag)
-        qof_instance_set_kvp (QOF_INSTANCE (cm), "auto_quote_control", NULL);
+        qof_instance_set_var_kvp (QOF_INSTANCE (cm), NULL, 1, "auto_quote_control");
     else
     {
         g_value_init (&v, G_TYPE_STRING);
         g_value_set_string (&v, "false");
-        qof_instance_set_kvp (QOF_INSTANCE (cm), "auto_quote_control", &v);
+        qof_instance_set_var_kvp (QOF_INSTANCE (cm), &v, 1, "auto_quote_control");
     }
     mark_commodity_dirty(cm);
     gnc_commodity_commit_edit(cm);
@@ -1456,10 +1456,10 @@ gnc_commodity_set_user_symbol(gnc_commodity * cm, const char * user_symbol)
     {
         g_value_init (&v, G_TYPE_STRING);
         g_value_set_string (&v, user_symbol);
-        qof_instance_set_kvp (QOF_INSTANCE(cm), "user_symbol", &v);
+        qof_instance_set_var_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol");
     }
     else
-        qof_instance_set_kvp (QOF_INSTANCE(cm), "user_symbol", NULL);
+        qof_instance_set_var_kvp (QOF_INSTANCE(cm), NULL, 1, "user_symbol");
 
     mark_commodity_dirty(cm);
     gnc_commodity_commit_edit(cm);
diff --git a/libgnucash/engine/gnc-lot.c b/libgnucash/engine/gnc-lot.c
index 77b3bec..896a39d 100644
--- a/libgnucash/engine/gnc-lot.c
+++ b/libgnucash/engine/gnc-lot.c
@@ -148,16 +148,13 @@ gnc_lot_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec*
         g_value_set_int(value, priv->marker);
         break;
     case PROP_INVOICE:
-        key = GNC_INVOICE_ID "/" GNC_INVOICE_GUID;
-        qof_instance_get_kvp (QOF_INSTANCE (lot), key, value);
+        qof_instance_get_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
         break;
     case PROP_OWNER_TYPE:
-        key = GNC_OWNER_ID"/" GNC_OWNER_TYPE;
-        qof_instance_get_kvp (QOF_INSTANCE (lot), key, value);
+        qof_instance_get_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_TYPE);
         break;
     case PROP_OWNER_GUID:
-        key = GNC_OWNER_ID "/" GNC_OWNER_GUID;
-        qof_instance_get_kvp (QOF_INSTANCE (lot), key, value);
+        qof_instance_get_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_GUID);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -191,16 +188,13 @@ gnc_lot_set_property (GObject* object,
         priv->marker = g_value_get_int(value);
         break;
     case PROP_INVOICE:
-        key = GNC_INVOICE_ID"/" GNC_INVOICE_GUID;
-        qof_instance_set_kvp (QOF_INSTANCE (lot), key, value);
+        qof_instance_set_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_INVOICE_ID, GNC_INVOICE_GUID);
         break;
     case PROP_OWNER_TYPE:
-        key = GNC_OWNER_ID "/" GNC_OWNER_TYPE;
-        qof_instance_set_kvp (QOF_INSTANCE (lot), key, value);
+        qof_instance_set_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_TYPE);
         break;
     case PROP_OWNER_GUID:
-        key = GNC_OWNER_ID "/" GNC_OWNER_GUID;
-        qof_instance_set_kvp (QOF_INSTANCE (lot), key, value);
+        qof_instance_set_var_kvp (QOF_INSTANCE (lot), value, 2, GNC_OWNER_ID, GNC_OWNER_GUID);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -433,7 +427,7 @@ gnc_lot_get_title (const GNCLot *lot)
 {
     GValue v = G_VALUE_INIT;
     if (!lot) return NULL;
-    qof_instance_get_kvp (QOF_INSTANCE (lot), "/title", &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (lot), &v, 1, "title");
     if (G_VALUE_HOLDS_STRING (&v))
         return g_value_get_string (&v);
     return NULL;
@@ -444,7 +438,7 @@ gnc_lot_get_notes (const GNCLot *lot)
 {
     GValue v = G_VALUE_INIT;
     if (!lot) return NULL;
-    qof_instance_get_kvp (QOF_INSTANCE (lot), "/notes", &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
     if (G_VALUE_HOLDS_STRING (&v))
         return g_value_get_string (&v);
     return NULL;
@@ -458,7 +452,7 @@ gnc_lot_set_title (GNCLot *lot, const char *str)
     qof_begin_edit(QOF_INSTANCE(lot));
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, str);
-    qof_instance_set_kvp (QOF_INSTANCE (lot), "/title", &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (lot), &v, 1, "title");
     qof_instance_set_dirty(QOF_INSTANCE(lot));
     gnc_lot_commit_edit(lot);
 }
@@ -471,7 +465,7 @@ gnc_lot_set_notes (GNCLot *lot, const char *str)
     qof_begin_edit(QOF_INSTANCE(lot));
     g_value_init (&v, G_TYPE_STRING);
     g_value_set_string (&v, str);
-    qof_instance_set_kvp (QOF_INSTANCE (lot), "/notes", &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (lot), &v, 1, "notes");
     qof_instance_set_dirty(QOF_INSTANCE(lot));
     gnc_lot_commit_edit(lot);
 }
diff --git a/libgnucash/engine/gncCustomer.c b/libgnucash/engine/gncCustomer.c
index 9b4ed80..b318e71 100644
--- a/libgnucash/engine/gncCustomer.c
+++ b/libgnucash/engine/gncCustomer.c
@@ -140,17 +140,14 @@ gnc_customer_get_property (GObject         *object,
         g_value_set_string(value, cust->name);
         break;
     case PROP_PDF_DIRNAME:
-	key = OWNER_EXPORT_PDF_DIRNAME;
-	qof_instance_get_kvp (QOF_INSTANCE (cust), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (cust), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        break;
     case PROP_LAST_POSTED:
-	key = LAST_POSTED_TO_ACCT;
-	qof_instance_get_kvp (QOF_INSTANCE (cust), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (cust), value, 1, LAST_POSTED_TO_ACCT);
+        break;
     case PROP_PAYMENT_LAST_ACCT:
-	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
-	qof_instance_get_kvp (QOF_INSTANCE (cust), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (cust), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -177,17 +174,14 @@ gnc_customer_set_property (GObject         *object,
         gncCustomerSetName(cust, g_value_get_string(value));
         break;
     case PROP_PDF_DIRNAME:
-	key = OWNER_EXPORT_PDF_DIRNAME;
-	qof_instance_set_kvp (QOF_INSTANCE (cust), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (cust), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        break;
     case PROP_LAST_POSTED:
-	key = LAST_POSTED_TO_ACCT;
-	qof_instance_set_kvp (QOF_INSTANCE (cust), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (cust), value, 1, LAST_POSTED_TO_ACCT);
+        break;
     case PROP_PAYMENT_LAST_ACCT:
-	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
-	qof_instance_set_kvp (QOF_INSTANCE (cust), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (cust), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
diff --git a/libgnucash/engine/gncEmployee.c b/libgnucash/engine/gncEmployee.c
index ebfb518..f41c388 100644
--- a/libgnucash/engine/gncEmployee.c
+++ b/libgnucash/engine/gncEmployee.c
@@ -128,10 +128,7 @@ gnc_employee_get_property (GObject         *object,
                            GParamSpec      *pspec)
 {
     GncEmployee *emp;
-    gchar *key;
-
     g_return_if_fail(GNC_IS_EMPLOYEE(object));
-
     emp = GNC_EMPLOYEE(object);
     switch (prop_id)
     {
@@ -166,17 +163,14 @@ gnc_employee_get_property (GObject         *object,
         g_value_take_object(value, emp->ccard_acc);
         break;
     case PROP_PDF_DIRNAME:
-	key = OWNER_EXPORT_PDF_DIRNAME;
-	qof_instance_get_kvp (QOF_INSTANCE (emp), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (emp), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        break;
     case PROP_LAST_POSTED:
-	key = LAST_POSTED_TO_ACCT;
-	qof_instance_get_kvp (QOF_INSTANCE (emp), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (emp), value, 1, LAST_POSTED_TO_ACCT);
+        break;
     case PROP_PAYMENT_LAST_ACCT:
-	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
-	qof_instance_get_kvp (QOF_INSTANCE (emp), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (emp), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -190,13 +184,9 @@ gnc_employee_set_property (GObject         *object,
                            GParamSpec      *pspec)
 {
     GncEmployee *emp;
-    gchar *key;
-
     g_return_if_fail(GNC_IS_EMPLOYEE(object));
-
     emp = GNC_EMPLOYEE(object);
     g_assert (qof_instance_get_editlevel(emp));
-
     switch (prop_id)
     {
     case PROP_USERNAME:
@@ -230,17 +220,14 @@ gnc_employee_set_property (GObject         *object,
         gncEmployeeSetCCard(emp, g_value_get_object(value));
         break;
     case PROP_PDF_DIRNAME:
-	key = OWNER_EXPORT_PDF_DIRNAME;
-	qof_instance_set_kvp (QOF_INSTANCE (emp), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (emp), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        break;
     case PROP_LAST_POSTED:
-	key = LAST_POSTED_TO_ACCT;
-	qof_instance_set_kvp (QOF_INSTANCE (emp), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (emp), value, 1, LAST_POSTED_TO_ACCT);
+        break;
     case PROP_PAYMENT_LAST_ACCT:
-	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
-	qof_instance_set_kvp (QOF_INSTANCE (emp), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (emp), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
diff --git a/libgnucash/engine/gncInvoice.c b/libgnucash/engine/gncInvoice.c
index 651865b..074270d 100644
--- a/libgnucash/engine/gncInvoice.c
+++ b/libgnucash/engine/gncInvoice.c
@@ -354,9 +354,9 @@ GncInvoice *gncInvoiceCopy (const GncInvoice *from)
     invoice->billing_id = CACHE_INSERT (from->billing_id);
     invoice->active = from->active;
 
-    qof_instance_get_kvp (QOF_INSTANCE (from), GNC_INVOICE_IS_CN, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (from), &v, 1, GNC_INVOICE_IS_CN);
     if (G_VALUE_HOLDS_INT64 (&v))
-         qof_instance_set_kvp (QOF_INSTANCE (invoice), GNC_INVOICE_IS_CN, &v);
+         qof_instance_set_var_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_IS_CN);
 
     invoice->terms = from->terms;
     gncBillTermIncRef (invoice->terms);
@@ -551,7 +551,7 @@ void gncInvoiceSetIsCreditNote (GncInvoice *invoice, gboolean credit_note)
     gncInvoiceBeginEdit (invoice);
     g_value_init (&v, G_TYPE_INT64);
     g_value_set_int64(&v, credit_note ? 1 : 0);
-    qof_instance_set_kvp (QOF_INSTANCE (invoice), GNC_INVOICE_IS_CN, &v);
+    qof_instance_set_var_kvp (QOF_INSTANCE (invoice), &v, 1, GNC_INVOICE_IS_CN);
     mark_invoice (invoice);
     gncInvoiceCommitEdit (invoice);
 
@@ -1040,7 +1040,7 @@ gboolean gncInvoiceGetIsCreditNote (const GncInvoice *invoice)
 {
     GValue v = G_VALUE_INIT;
     if (!invoice) return FALSE;
-    qof_instance_get_kvp (QOF_INSTANCE(invoice), GNC_INVOICE_IS_CN, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE(invoice), &v, 1, GNC_INVOICE_IS_CN);
     if (G_VALUE_HOLDS_INT64(&v) && g_value_get_int64(&v))
         return TRUE;
     else
diff --git a/libgnucash/engine/gncJob.c b/libgnucash/engine/gncJob.c
index bd4c672..5d76c29 100644
--- a/libgnucash/engine/gncJob.c
+++ b/libgnucash/engine/gncJob.c
@@ -120,8 +120,7 @@ gnc_job_get_property (GObject         *object,
         g_value_set_string(value, job->name);
         break;
     case PROP_PDF_DIRNAME:
-        key = OWNER_EXPORT_PDF_DIRNAME;
-        qof_instance_get_kvp (QOF_INSTANCE (job), key, value);
+        qof_instance_get_var_kvp (QOF_INSTANCE (job), value, 1, OWNER_EXPORT_PDF_DIRNAME);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -149,8 +148,7 @@ gnc_job_set_property (GObject         *object,
         gncJobSetName(job, g_value_get_string(value));
         break;
     case PROP_PDF_DIRNAME:
-        key = OWNER_EXPORT_PDF_DIRNAME;
-        qof_instance_set_kvp (QOF_INSTANCE (job), key, value);
+        qof_instance_set_var_kvp (QOF_INSTANCE (job), value, 1, OWNER_EXPORT_PDF_DIRNAME);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -318,11 +316,11 @@ void gncJobSetRate (GncJob *job, gnc_numeric rate)
         GValue v = G_VALUE_INIT;
         g_value_init (&v, GNC_TYPE_NUMERIC);
         g_value_set_boxed (&v, &rate);
-        qof_instance_set_kvp (QOF_INSTANCE (job), GNC_JOB_RATE, &v);
+        qof_instance_set_var_kvp (QOF_INSTANCE (job), &v, 1, GNC_JOB_RATE);
     }
     else
     {
-        qof_instance_set_kvp (QOF_INSTANCE (job), GNC_JOB_RATE, NULL);
+        qof_instance_set_var_kvp (QOF_INSTANCE (job), NULL, 1, GNC_JOB_RATE);
     }
     mark_job (job);
     gncJobCommitEdit (job);
@@ -456,7 +454,7 @@ gnc_numeric gncJobGetRate (const GncJob *job)
     GValue v = G_VALUE_INIT;
     gnc_numeric *rate = NULL;
     if (!job) return gnc_numeric_zero ();
-    qof_instance_get_kvp (QOF_INSTANCE (job), GNC_JOB_RATE, &v);
+    qof_instance_get_var_kvp (QOF_INSTANCE (job), &v, 1, GNC_JOB_RATE);
     if (G_VALUE_HOLDS_BOXED (&v))
         rate = (gnc_numeric*)g_value_get_boxed (&v);
     if (rate)
diff --git a/libgnucash/engine/gncVendor.c b/libgnucash/engine/gncVendor.c
index 3ebdb2b..1df3fab 100644
--- a/libgnucash/engine/gncVendor.c
+++ b/libgnucash/engine/gncVendor.c
@@ -179,17 +179,14 @@ gnc_vendor_get_property (GObject         *object,
         g_value_set_string(value, qofVendorGetTaxIncluded(vendor));
         break;
     case PROP_PDF_DIRNAME:
-	key = OWNER_EXPORT_PDF_DIRNAME;
-	qof_instance_get_kvp (QOF_INSTANCE (vendor), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (vendor), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        break;
     case PROP_LAST_POSTED:
-	key = LAST_POSTED_TO_ACCT;
-	qof_instance_get_kvp (QOF_INSTANCE (vendor), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (vendor), value, 1, LAST_POSTED_TO_ACCT);
+        break;
     case PROP_PAYMENT_LAST_ACCT:
-	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
-	qof_instance_get_kvp (QOF_INSTANCE (vendor), key, value);
-	break;
+        qof_instance_get_var_kvp (QOF_INSTANCE (vendor), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -246,17 +243,14 @@ gnc_vendor_set_property (GObject         *object,
         qofVendorSetTaxIncluded(vendor, g_value_get_string(value));
         break;
     case PROP_PDF_DIRNAME:
-	key = OWNER_EXPORT_PDF_DIRNAME;
-	qof_instance_set_kvp (QOF_INSTANCE (vendor), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (vendor), value, 1, OWNER_EXPORT_PDF_DIRNAME);
+        break;
     case PROP_LAST_POSTED:
-	key = LAST_POSTED_TO_ACCT;
-	qof_instance_set_kvp (QOF_INSTANCE (vendor), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (vendor), value, 1, LAST_POSTED_TO_ACCT);
+        break;
     case PROP_PAYMENT_LAST_ACCT:
-	key = GNC_PAYMENT "/" GNC_LAST_ACCOUNT;
-	qof_instance_set_kvp (QOF_INSTANCE (vendor), key, value);
-	break;
+        qof_instance_set_var_kvp (QOF_INSTANCE (vendor), value, 2, GNC_PAYMENT, GNC_LAST_ACCOUNT);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
diff --git a/libgnucash/engine/kvp-frame.cpp b/libgnucash/engine/kvp-frame.cpp
index 29fe927..eff478a 100644
--- a/libgnucash/engine/kvp-frame.cpp
+++ b/libgnucash/engine/kvp-frame.cpp
@@ -84,6 +84,11 @@ make_vector(std::string key)
     return path;
 }
 
+/*
+ * If the key is delimited, calls set(path) with the parsed result
+ * otherwise, inserts the key and value locally and returns the
+ * old value if there was one.
+ */
 KvpValue*
 KvpFrameImpl::set(const char* key, KvpValue* value) noexcept
 {
@@ -123,6 +128,10 @@ walk_path_or_nullptr(const KvpFrameImpl* frame, Path& path)
     return cur_frame;
 }
 
+/*
+ * If the last path parameter has a delimiter, the path before that point is ignored,
+ * and set is called with only the last parameter with the delimiter as the key.
+ */
 KvpValue*
 KvpFrameImpl::set(Path path, KvpValue* value) noexcept
 {
diff --git a/libgnucash/engine/kvp-frame.hpp b/libgnucash/engine/kvp-frame.hpp
index 49572b8..6bdb16f 100644
--- a/libgnucash/engine/kvp-frame.hpp
+++ b/libgnucash/engine/kvp-frame.hpp
@@ -44,12 +44,8 @@
  * KVP modifications are written to the database. Two generic abstractions are
  * provided:
  *
- * * @ref qof_instance_set_kvp and @ref qof_instance_get_kvp provide single-item
-     access via GValues to support object properties.
-
  * * @ref qof_book_set_option and @ref qof_book_get_option provide similar
-     access for book options.
-
+ *   access for book options.
  *
  * @ref kvpvalues provides a catolog of KVP entries including what objects
  * they're part of and how they're used.
diff --git a/libgnucash/engine/qofbook.cpp b/libgnucash/engine/qofbook.cpp
index 4a57af9..1694ec4 100644
--- a/libgnucash/engine/qofbook.cpp
+++ b/libgnucash/engine/qofbook.cpp
@@ -142,62 +142,40 @@ qof_book_get_property (GObject* object,
     switch (prop_id)
     {
     case PROP_OPT_TRADING_ACCOUNTS:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-			       OPTION_NAME_TRADING_ACCOUNTS);
-	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_TRADING_ACCOUNTS});
+        break;
     case PROP_OPT_BOOK_CURRENCY:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-                   OPTION_NAME_BOOK_CURRENCY);
-	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_BOOK_CURRENCY});
+        break;
     case PROP_OPT_DEFAULT_GAINS_POLICY:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-                   OPTION_NAME_DEFAULT_GAINS_POLICY);
-	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_DEFAULT_GAINS_POLICY});
+        break;
     case PROP_OPT_DEFAULT_GAINS_ACCOUNT_GUID:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-                   OPTION_NAME_DEFAULT_GAINS_LOSS_ACCT_GUID);
-	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_DEFAULT_GAINS_LOSS_ACCT_GUID});
+        break;
     case PROP_OPT_AUTO_READONLY_DAYS:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-			       OPTION_NAME_AUTO_READONLY_DAYS);
-	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_AUTO_READONLY_DAYS});
+        break;
     case PROP_OPT_NUM_FIELD_SOURCE:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-			       OPTION_NAME_NUM_FIELD_SOURCE);
-	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_NUM_FIELD_SOURCE});
+        break;
     case PROP_OPT_DEFAULT_BUDGET:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-			       OPTION_NAME_DEFAULT_BUDGET);
-	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_DEFAULT_BUDGET});
+        break;
     case PROP_OPT_FY_END:
-	key = const_cast<char*>("fy_end");
-	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
-	break;
+        qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {"fy_end"});
+        break;
     case PROP_AB_TEMPLATES:
-	key = const_cast<char*>(AB_KEY "/" AB_TEMPLATES);
-	qof_instance_get_kvp (QOF_INSTANCE (book), key, value);
-	break;
+        key = const_cast<char*>(AB_KEY "/" AB_TEMPLATES);
+        qof_instance_get_path_kvp (QOF_INSTANCE (book), value, {"AB_KEY", "AB_TEMPLATES"});
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -220,62 +198,39 @@ qof_book_set_property (GObject      *object,
     switch (prop_id)
     {
     case PROP_OPT_TRADING_ACCOUNTS:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-			       OPTION_NAME_TRADING_ACCOUNTS);
-	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_TRADING_ACCOUNTS});
+        break;
     case PROP_OPT_BOOK_CURRENCY:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-                   OPTION_NAME_BOOK_CURRENCY);
-	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_BOOK_CURRENCY});
+        break;
     case PROP_OPT_DEFAULT_GAINS_POLICY:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-                   OPTION_NAME_DEFAULT_GAINS_POLICY);
-	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_DEFAULT_GAINS_POLICY});
+        break;
     case PROP_OPT_DEFAULT_GAINS_ACCOUNT_GUID:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-                   OPTION_NAME_DEFAULT_GAINS_LOSS_ACCT_GUID);
-	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_DEFAULT_GAINS_LOSS_ACCT_GUID});
+        break;
     case PROP_OPT_AUTO_READONLY_DAYS:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-			       OPTION_NAME_AUTO_READONLY_DAYS);
-	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_AUTO_READONLY_DAYS});
+        break;
     case PROP_OPT_NUM_FIELD_SOURCE:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-			       OPTION_NAME_NUM_FIELD_SOURCE);
-	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_NUM_FIELD_SOURCE});
+        break;
     case PROP_OPT_DEFAULT_BUDGET:
-	key = g_strdup_printf ("%s/%s/%s", KVP_OPTION_PATH,
-			       OPTION_SECTION_ACCOUNTS,
-			       OPTION_NAME_DEFAULT_BUDGET);
-	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
-	g_free (key);
-	break;
+        qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {KVP_OPTION_PATH,
+                OPTION_SECTION_ACCOUNTS, OPTION_NAME_DEFAULT_BUDGET});
+        break;
     case PROP_OPT_FY_END:
-	key = const_cast<char*>("fy_end");
-	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
-	break;
+        qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {"fy_end"});
+        break;
     case PROP_AB_TEMPLATES:
-	key = const_cast<char*>(AB_KEY "/" AB_TEMPLATES);
-	qof_instance_set_kvp (QOF_INSTANCE (book), key, value);
-	break;
+        qof_instance_set_path_kvp (QOF_INSTANCE (book), value, {AB_KEY, AB_TEMPLATES});
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
diff --git a/libgnucash/engine/qofinstance-p.h b/libgnucash/engine/qofinstance-p.h
index 5ffcd9f..a54a581 100644
--- a/libgnucash/engine/qofinstance-p.h
+++ b/libgnucash/engine/qofinstance-p.h
@@ -25,6 +25,7 @@
  *
  * Copyright (C) 2003 Linas Vepstas <linas at linas.org>
  * Copyright (c) 2007 David Hampton <hampton at employees.org>
+ * Copyright 2017 Aaron Laws <dartme18 at gmail.com>
  */
 
 #ifndef QOF_INSTANCE_P_H
@@ -115,23 +116,24 @@ void qof_instance_set_idata(gpointer inst, guint32 idata);
  * @return TRUE if Kvp isn't empty.
  */
 gboolean qof_instance_has_kvp (QofInstance *inst);
-/** Sets a KVP slot to a value from a GValue. The key can be a '/'-delimited
- * path, and intermediate container frames will be created if necessary.
- * Commits the change to the QofInstance.
+
+/** Sets a KVP slot to a value from a GValue. Intermediate container
+ * frames will be created if necessary. Commits the change to the QofInstance.
  * @param inst: The QofInstance on which to set the value.
- * @param key: The key for the slot or '/'-delimited path
+ * @param key: The path to the slot.
  * @param value: A GValue containing an item of a type which KvpValue knows
- * how to store.
+ *           how to store.
  */
-void qof_instance_set_kvp (QofInstance *inst, const gchar *key, const GValue *value);
+void qof_instance_set_var_kvp (QofInstance *, GValue const * value, unsigned count, ...);
+
 /** Retrieves the contents of a KVP slot into a provided GValue.
  * @param inst: The QofInstance
- * @param key: The key of or '/'-delimited path to the slot.
+ * @param key: The path to the slot.
  * @param value: A GValue into which to store the value of the slot. It will be
  *               set to the correct type.
  */
-void qof_instance_get_kvp (const QofInstance *inst, const gchar *key, GValue
-*value);
+void qof_instance_get_var_kvp (QofInstance *, GValue * value, unsigned count, ...);
+
 /** @} Close out the DOxygen ingroup */
 /* Functions to isolate the KVP mechanism inside QOF for cases where
 GValue * operations won't work.
@@ -151,7 +153,9 @@ gboolean qof_instance_kvp_has_guid (const QofInstance *inst, const char *path,
 void qof_instance_kvp_merge_guids (const QofInstance *target,
                                    const QofInstance *donor, const char* path);
 gboolean qof_instance_has_slot (const QofInstance *inst, const char *path);
+void qof_instance_slot_var_delete (const QofInstance *, unsigned count, ...);
 void qof_instance_slot_delete (const QofInstance *inst, const char *path);
+void qof_instance_slot_var_delete_if_empty (const QofInstance *, unsigned count, ...);
 void qof_instance_slot_delete_if_empty (const QofInstance *inst,
                                         const char *path);
 void qof_instance_foreach_slot (const QofInstance *inst, const char *path,
@@ -160,6 +164,15 @@ void qof_instance_foreach_slot (const QofInstance *inst, const char *path,
 #ifdef __cplusplus
 } /* extern "C" */
 
+void qof_instance_get_path_kvp (QofInstance *, GValue *, std::vector<std::string> const &);
+
+void qof_instance_set_path_kvp (QofInstance *, GValue const *, std::vector<std::string> const &);
+
+bool qof_instance_has_path_slot (QofInstance const *, std::vector<std::string> const &);
+
+void qof_instance_slot_path_delete (QofInstance const *, std::vector<std::string> const &);
+
+void qof_instance_slot_path_delete_if_empty (QofInstance const *, std::vector<std::string> const &);
 /** Returns all keys that match the given prefix and their corresponding values.*/
 std::map<std::string, KvpValue*>
 qof_instance_get_slots_prefix (QofInstance const *, std::string const & prefix);
diff --git a/libgnucash/engine/qofinstance.cpp b/libgnucash/engine/qofinstance.cpp
index 7994fb9..64826d5 100644
--- a/libgnucash/engine/qofinstance.cpp
+++ b/libgnucash/engine/qofinstance.cpp
@@ -26,6 +26,7 @@
  *
  * Copyright (C) 2003 Linas Vepstas <linas at linas.org>
  * Copyright (c) 2007 David Hampton <hampton at employees.org>
+ * Copyright 2017 Aaron Laws <dartme18 at gmail.com>
  */
 
 #include "guid.hpp"
@@ -1059,23 +1060,53 @@ qof_instance_has_kvp (QofInstance *inst)
     return (inst->kvp_data != NULL && !inst->kvp_data->empty());
 }
 
-void
-qof_instance_set_kvp (QofInstance *inst, const gchar *key, const GValue *value)
+void qof_instance_set_path_kvp (QofInstance * inst, GValue const * value, std::vector<std::string> const & path)
 {
-    delete inst->kvp_data->set_path(key, kvp_value_from_gvalue(value));
+    delete inst->kvp_data->set_path (path, kvp_value_from_gvalue (value));
 }
 
 void
-qof_instance_get_kvp (const QofInstance *inst, const gchar *key, GValue *value)
+qof_instance_set_var_kvp (QofInstance * inst, GValue const * value, unsigned count, ...)
 {
-    auto temp = gvalue_from_kvp_value (inst->kvp_data->get_slot(key));
+    std::vector<std::string> path;
+    va_list args;
+    va_start (args, count);
+    for (unsigned i{0}; i < count; ++i)
+        path.push_back (va_arg (args, char const *));
+    va_end (args);
+    delete inst->kvp_data->set_path (path, kvp_value_from_gvalue (value));
+}
+
+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);
+        g_value_copy (temp, value);
+        gnc_gvalue_free (temp);
+    }
+}
+
+void
+qof_instance_get_var_kvp (QofInstance * inst, GValue * value, unsigned count, ...)
+{
+    std::vector<std::string> path;
+    va_list args;
+    va_start (args, count);
+    for (unsigned i{0}; i < count; ++i)
+        path.push_back (va_arg (args, char const *));
+    va_end (args);
+    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);
     }
 }
 
@@ -1115,16 +1146,16 @@ qof_instance_kvp_add_guid (const QofInstance *inst, const char* path,
     auto container = new KvpFrame;
     container->set(key, new KvpValue(const_cast<GncGUID*>(guid)));
     container->set("date", new KvpValue(time));
-    delete inst->kvp_data->set_path(path, new KvpValue(container));
+    delete inst->kvp_data->set_path({path}, new KvpValue(container));
 }
 
 inline static gboolean
-kvp_match_guid (KvpValue *v, const char *key, const GncGUID *guid)
+kvp_match_guid (KvpValue *v, std::vector<std::string> const & path, const GncGUID *guid)
 {
     if (v->get_type() != KvpValue::Type::FRAME)
         return FALSE;
     auto frame = v->get<KvpFrame*>();
-    auto val = frame->get_slot(key);
+    auto val = frame->get_slot(path);
     if (val == nullptr || val->get_type() != KvpValue::Type::GUID)
         return FALSE;
     auto this_guid = val->get<GncGUID*>();
@@ -1139,13 +1170,13 @@ qof_instance_kvp_has_guid (const QofInstance *inst, const char *path,
     g_return_val_if_fail (inst->kvp_data != NULL, FALSE);
     g_return_val_if_fail (guid != NULL, FALSE);
 
-    auto v = inst->kvp_data->get_slot(path);
+    auto v = inst->kvp_data->get_slot({path});
     if (v == nullptr) return FALSE;
 
     switch (v->get_type())
     {
     case KvpValue::Type::FRAME:
-        return kvp_match_guid (v, key, guid);
+        return kvp_match_guid (v, {key}, guid);
         break;
     case KvpValue::Type::GLIST:
     {
@@ -1153,7 +1184,7 @@ qof_instance_kvp_has_guid (const QofInstance *inst, const char *path,
         for (auto node = list; node != NULL; node = node->next)
         {
             auto val = static_cast<KvpValue*>(node->data);
-            if (kvp_match_guid (val, key, guid))
+            if (kvp_match_guid (val, {key}, guid))
             {
                 return TRUE;
             }
@@ -1174,15 +1205,15 @@ qof_instance_kvp_remove_guid (const QofInstance *inst, const char *path,
     g_return_if_fail (inst->kvp_data != NULL);
     g_return_if_fail (guid != NULL);
 
-    auto v = inst->kvp_data->get_slot(path);
+    auto v = inst->kvp_data->get_slot({path});
     if (v == NULL) return;
 
     switch (v->get_type())
     {
     case KvpValue::Type::FRAME:
-        if (kvp_match_guid (v, key, guid))
+        if (kvp_match_guid (v, {key}, guid))
         {
-            delete inst->kvp_data->set_path(path, nullptr);
+            delete inst->kvp_data->set_path({path}, nullptr);
             delete v;
         }
         break;
@@ -1192,7 +1223,7 @@ qof_instance_kvp_remove_guid (const QofInstance *inst, const char *path,
         for (auto node = list; node != nullptr; node = node->next)
         {
             auto val = static_cast<KvpValue*>(node->data);
-            if (kvp_match_guid (val, key, guid))
+            if (kvp_match_guid (val, {key}, guid))
             {
                 list = g_list_delete_link (list, node);
                 v->set(list);
@@ -1216,19 +1247,19 @@ qof_instance_kvp_merge_guids (const QofInstance *target,
     g_return_if_fail (target != NULL);
     g_return_if_fail (donor != NULL);
 
-    if (! qof_instance_has_slot (donor, path)) return;
-    auto v = donor->kvp_data->get_slot(path);
+    if (! qof_instance_has_slot (donor, {path})) return;
+    auto v = donor->kvp_data->get_slot({path});
     if (v == NULL) return;
 
-    auto target_val = target->kvp_data->get_slot(path);
+    auto target_val = target->kvp_data->get_slot({path});
     switch (v->get_type())
     {
     case KvpValue::Type::FRAME:
         if (target_val)
             target_val->add(v);
         else
-            target->kvp_data->set_path(path, v);
-        donor->kvp_data->set(path, nullptr); //Contents moved, Don't delete!
+            target->kvp_data->set_path({path}, v);
+        donor->kvp_data->set({path}, nullptr); //Contents moved, Don't delete!
         break;
     case KvpValue::Type::GLIST:
         if (target_val)
@@ -1238,8 +1269,8 @@ qof_instance_kvp_merge_guids (const QofInstance *target,
             target_val->set(list);
         }
         else
-            target->kvp_data->set(path, v);
-        donor->kvp_data->set(path, nullptr); //Contents moved, Don't delete!
+            target->kvp_data->set({path}, v);
+        donor->kvp_data->set({path}, nullptr); //Contents moved, Don't delete!
         break;
     default:
         PWARN ("Instance KVP on path %s contains the wrong type.", path);
@@ -1247,16 +1278,67 @@ qof_instance_kvp_merge_guids (const QofInstance *target,
     }
 }
 
+bool qof_instance_has_path_slot (QofInstance const * inst, std::vector<std::string> const & path)
+{
+    return inst->kvp_data->get_slot (path) != nullptr;
+}
+
 gboolean
 qof_instance_has_slot (const QofInstance *inst, const char *path)
 {
     return inst->kvp_data->get_slot(path) != NULL;
 }
 
+void qof_instance_slot_path_delete (QofInstance const * inst, std::vector<std::string> const & path)
+{
+    delete inst->kvp_data->set (path, nullptr);
+}
+
+void
+qof_instance_slot_var_delete (QofInstance const *inst, unsigned count, ...)
+{
+    std::vector<std::string> path;
+    va_list args;
+    va_start (args, count);
+    for (unsigned i{0}; i < count; ++i)
+        path.push_back (va_arg (args, char const *));
+    va_end (args);
+    delete inst->kvp_data->set (path, nullptr);
+}
+
 void
 qof_instance_slot_delete (const QofInstance *inst, const char *path)
 {
-    inst->kvp_data->set(path, nullptr);
+    delete inst->kvp_data->set(path, nullptr);
+}
+
+void qof_instance_slot_path_delete_if_empty (QofInstance const * inst, std::vector<std::string> const & path)
+{
+    auto slot = inst->kvp_data->get_slot (path);
+    if (slot)
+    {
+        auto frame = slot->get <KvpFrame*> ();
+        if (frame && frame->empty())
+            delete inst->kvp_data->set (path, nullptr);
+    }
+}
+
+void
+qof_instance_slot_var_delete_if_empty (QofInstance const *inst, unsigned count, ...)
+{
+    std::vector<std::string> path;
+    va_list args;
+    va_start (args, count);
+    for (unsigned i{0}; i < count; ++i)
+        path.push_back (va_arg (args, char const *));
+    va_end (args);
+    auto slot = inst->kvp_data->get_slot (path);
+    if (slot)
+    {
+        auto frame = slot->get <KvpFrame*> ();
+        if (frame && frame->empty ())
+            delete inst->kvp_data->set (path, nullptr);
+    }
 }
 
 void
@@ -1267,9 +1349,10 @@ qof_instance_slot_delete_if_empty (const QofInstance *inst, const char *path)
     {
         auto frame = slot->get<KvpFrame*>();
         if (frame && frame->empty())
-            inst->kvp_data->set(path, nullptr);
+            delete inst->kvp_data->set(path, nullptr);
     }
 }
+
 namespace {
 struct wrap_param
 {

commit eb6dad86e3dc48ceaebf586b280b1fc09d8087b7
Author: lmat <dartme18 at gmail.com>
Date:   Fri Oct 27 11:09:42 2017 -0400

    Fixed conversion problem
    
    The conversion assumed there were only three levels to bayes import
    map kvp: IMAP token, user-supplied token, GUID/account name. In
    actuality, since user-supplied tokens could have the delimiter in them,
    there could be several. This fix takes that into account like so:
    IMAP token, potentially several user-supplied tokens, GUID/account name.
    
    The import map is undergoing two conversions at the same time: account names
    to guids and an hierarchical representation to a flat representation in KVP.

diff --git a/gnucash/gnome-utils/gnc-file.c b/gnucash/gnome-utils/gnc-file.c
index 96821e5..12d5e59 100644
--- a/gnucash/gnome-utils/gnc-file.c
+++ b/gnucash/gnome-utils/gnc-file.c
@@ -1026,7 +1026,6 @@ RESTART:
     // Convert imap mappings from account full name to guid strings
     qof_event_suspend();
     gnc_account_imap_convert_bayes (gnc_get_current_book());
-    gnc_account_imap_convert_flat (gnc_get_current_book());
     qof_event_resume();
 
     return TRUE;
diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index a3603e9..8ce126d 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -43,6 +43,8 @@
 #include "gnc-features.h"
 #include "guid.hpp"
 
+#include <numeric>
+
 static QofLogModule log_module = GNC_MOD_ACCOUNT;
 
 /* The Canonical Account Separator.  Pre-Initialized. */
@@ -5269,8 +5271,8 @@ get_first_pass_probabilities(GncImportMatchMap * imap, GList * tokens)
      * in the input tokens list. */
     for (auto current_token = tokens; current_token; current_token = current_token->next)
     {
-        auto translated_token = std::string{static_cast<char const *>(current_token->data)};
-        std::replace(translated_token.begin(), translated_token.end(), '/', '-');
+        auto translated_token = std::string {static_cast <char const *> (current_token->data)};
+        std::replace (translated_token.begin (), translated_token.end (), '/', '-');
         token_accounts_info tokenInfo{};
         auto path = std::string{IMAP_FRAME_BAYES "-"} + translated_token;
         qof_instance_foreach_slot_prefix (QOF_INSTANCE (imap->acc), path, &build_token_info, tokenInfo);
@@ -5331,7 +5333,7 @@ gnc_account_imap_find_account_bayes (GncImportMatchMap *imap, GList *tokens)
 }
 
 static void
-change_imap_entry (GncImportMatchMap *imap, gchar *kvp_path, int64_t token_count)
+change_imap_entry (GncImportMatchMap *imap, gchar const * kvp_path, int64_t token_count)
 {
     GValue value = G_VALUE_INIT;
 
@@ -5377,7 +5379,7 @@ gnc_account_imap_add_account_bayes (GncImportMatchMap *imap,
 {
     GList *current_token;
     gint64 token_count;
-    char *account_fullname, *kvp_path;
+    char *account_fullname;
     char *guid_string;
 
     ENTER(" ");
@@ -5405,28 +5407,20 @@ gnc_account_imap_add_account_bayes (GncImportMatchMap *imap,
                  skip this case here. */
         if (!current_token->data || (*((char*)current_token->data) == '\0'))
             continue;
-
         /* start off with one token for this account */
         token_count = 1;
-
         PINFO("adding token '%s'", (char*)current_token->data);
-
-        std::string translated_token {static_cast<char*>(current_token->data)};
-        std::replace(translated_token.begin(), translated_token.end(), '/', '-');
-        kvp_path = g_strdup_printf (IMAP_FRAME_BAYES "-%s-%s",
-                                    translated_token.c_str(),
-                                    guid_string);
+        std::string translated_token {static_cast <char*> (current_token->data)};
+        std::replace (translated_token.begin (), translated_token.end (), '/', '-');
+        auto path = std::string {IMAP_FRAME_BAYES} + '-' + translated_token + '-' + guid_string;
         /* change the imap entry for the account */
-        change_imap_entry (imap, kvp_path, token_count);
-        g_free (kvp_path);
+        change_imap_entry (imap, path.c_str (), token_count);
     }
-
     /* free up the account fullname and guid string */
     qof_instance_set_dirty (QOF_INSTANCE (imap->acc));
     xaccAccountCommitEdit (imap->acc);
     g_free (account_fullname);
     g_free (guid_string);
-
     LEAVE(" ");
 }
 
@@ -5655,68 +5649,48 @@ look_for_old_separator_descendants (Account *root, gchar const *full_name, const
     return new_name;
 }
 
-static Account *
-look_for_old_mapping (GncImapInfo *imapInfo)
+static std::string
+get_guid_from_account_name (Account * root, std::string const & name)
 {
-    Account       *root, *map_account = NULL;
-    const gchar   *sep = gnc_get_account_separator_string ();
-    gchar         *full_name;
-
-    PINFO("Category Head is '%s', Full Category is '%s'", imapInfo->category_head, imapInfo->full_category);
-
-    // do we have a map_account all ready, implying a guid string
-    if (imapInfo->map_account != NULL)
-        return NULL;
-
-    root = gnc_account_get_root (imapInfo->source_account);
-
-    full_name = g_strdup (imapInfo->full_category + strlen (imapInfo->category_head) + 1);
-
-    // may be top level or match with existing separator
-    map_account = gnc_account_lookup_by_full_name (root, full_name);
-
-    // do we have a valid account, if not, look for old separator
-    if (map_account == NULL)
+    auto map_account = gnc_account_lookup_by_full_name (root, name.c_str ());
+    if (!map_account)
     {
-        gchar * temp_name = look_for_old_separator_descendants (root, full_name, sep);
-        g_free(full_name);
-        full_name = temp_name;
-        map_account = gnc_account_lookup_by_full_name (root, full_name); // lets try again
+        auto temp_account_name = look_for_old_separator_descendants (root, name.c_str (),
+             gnc_get_account_separator_string ());
+        map_account = gnc_account_lookup_by_full_name (root, temp_account_name);
+        g_free (temp_account_name);
     }
+    auto temp_guid = gnc::GUID {*xaccAccountGetGUID (map_account)};
+    return temp_guid.to_string ();
+}
 
-    PINFO("Full account name is '%s'", full_name);
-
-    g_free (full_name);
-
-    return map_account;
+static std::pair <std::string, KvpValue*>
+convert_entry (std::pair <std::vector <std::string>, KvpValue*> entry, Account* root)
+{
+    auto const & account_name = entry.first.back();
+    entry.first.pop_back();
+    auto guid_str = get_guid_from_account_name (root, account_name);
+    entry.first.emplace_back ("/");
+    entry.first.emplace_back (guid_str);
+    std::string new_key {std::accumulate (entry.first.begin(), entry.first.end(), std::string {})};
+    new_key = IMAP_FRAME_BAYES + new_key;
+    std::replace (new_key.begin(), new_key.end(), '/', '-');
+    return {new_key, entry.second};
 }
 
 static std::vector<std::pair<std::string, KvpValue*>>
 get_new_guid_imap (Account * acc)
 {
     auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
-    auto slot = frame->get_slot(IMAP_FRAME_BAYES);
+    auto slot = frame->get_slot (IMAP_FRAME_BAYES);
     if (!slot)
         return {};
-    std::string const imap_frame_str {IMAP_FRAME_BAYES};
-    std::vector<std::pair<std::string, KvpValue*>> ret;
+    auto imap_frame = slot->get<KvpFrame*> ();
+    auto flat_kvp = imap_frame->flatten_kvp ();
     auto root = gnc_account_get_root (acc);
-    auto imap_frame = slot->get<KvpFrame*>();
-    imap_frame->for_each_slot_temp ([&ret, root, &imap_frame_str] (char const * token, KvpValue* val) {
-        auto token_frame = val->get<KvpFrame*>();
-        token_frame->for_each_slot_temp ([&ret, root, &imap_frame_str, token] (char const * account_name, KvpValue* val) {
-            auto map_account = gnc_account_lookup_by_full_name (root, account_name);
-            if (!map_account)
-            {
-                auto temp_account_name = look_for_old_separator_descendants (root, account_name, gnc_get_account_separator_string());
-                map_account = gnc_account_lookup_by_full_name (root, temp_account_name);
-                g_free (temp_account_name);
-            }
-            auto temp_guid = gnc::GUID{*xaccAccountGetGUID (map_account)};
-            auto guid_str = temp_guid.to_string();
-            ret.push_back({imap_frame_str + "-" + token + "-" + guid_str, val});
-        });
-    });
+    std::vector <std::pair <std::string, KvpValue*>> ret;
+    for (auto const & flat_entry : flat_kvp)
+        ret.emplace_back (convert_entry (flat_entry, root));
     return ret;
 }
 
@@ -5737,7 +5711,6 @@ convert_imap_account_bayes_to_guid (Account *acc)
 }
 
 char const * run_once_key_to_guid {"changed-bayesian-to-guid"};
-char const * run_once_key_to_flat {"changed-bayesian-to-flat"};
 
 static void
 imap_convert_bayes_to_guid (QofBook * book)
@@ -5752,55 +5725,6 @@ imap_convert_bayes_to_guid (QofBook * book)
     g_list_free (accts);
 }
 
-static std::vector<std::pair<std::string, KvpValue*>>
-get_new_flat_imap (Account * acc)
-{
-    auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
-    auto slot = frame->get_slot(IMAP_FRAME_BAYES);
-    if (!slot)
-        return {};
-    std::string const imap_frame_str {IMAP_FRAME_BAYES};
-    std::vector<std::pair<std::string, KvpValue*>> ret;
-    auto root = gnc_account_get_root (acc);
-    auto imap_frame = slot->get<KvpFrame*>();
-    imap_frame->for_each_slot_temp ([&ret, &imap_frame_str] (char const * token, KvpValue* val) {
-        auto token_frame = val->get<KvpFrame*>();
-        token_frame->for_each_slot_temp ([&ret, &imap_frame_str, token] (char const * account_guid, KvpValue* val) {
-            ret.push_back({imap_frame_str + "-" + token + "-" + account_guid, val});
-        });
-    });
-    return ret;
-}
-
-static void
-convert_imap_account_bayes_to_flat (Account * acc)
-{
-    auto flat_imap = get_new_flat_imap (acc);
-    if (!flat_imap.size())
-        return;
-    auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
-    xaccAccountBeginEdit(acc);
-    frame->set(IMAP_FRAME_BAYES, nullptr);
-    std::for_each(flat_imap.begin(), flat_imap.end(), [&frame] (std::pair<std::string, KvpValue*> const & entry) {
-        frame->set(entry.first.c_str(), entry.second);
-    });
-    qof_instance_set_dirty (QOF_INSTANCE (acc));
-    xaccAccountCommitEdit(acc);
-}
-
-static void
-imap_convert_bayes_to_flat (QofBook * book)
-{
-    auto root = gnc_book_get_root_account (book);
-    auto accts = gnc_account_get_descendants_sorted (root);
-    for (auto ptr = accts; ptr; ptr = g_list_next (ptr))
-    {
-        Account *acc = static_cast <Account*> (ptr->data);
-        convert_imap_account_bayes_to_flat (acc);
-    }
-    g_list_free (accts);
-}
-
 static bool
 run_once_key_set (char const * key, QofBook * book)
 {
@@ -5819,21 +5743,12 @@ set_run_once_key (char const * key, QofBook * book)
 }
 
 void
-gnc_account_imap_convert_flat (QofBook *book)
-{
-    if (run_once_key_set(run_once_key_to_flat, book))
-        return;
-    imap_convert_bayes_to_flat (book);
-    set_run_once_key(run_once_key_to_flat, book);
-}
-
-void
 gnc_account_imap_convert_bayes (QofBook *book)
 {
-    if (run_once_key_set(run_once_key_to_guid, book))
+    if (run_once_key_set (run_once_key_to_guid, book))
         return;
-    imap_convert_bayes_to_guid(book);
-    set_run_once_key(run_once_key_to_guid, book);
+    imap_convert_bayes_to_guid (book);
+    set_run_once_key (run_once_key_to_guid, book);
 }
 
 /* ================================================================ */
@@ -5843,7 +5758,6 @@ static void
 gnc_account_book_end(QofBook* book)
 {
     Account *root_account = gnc_book_get_root_account(book);
-
     xaccAccountBeginEdit(root_account);
     xaccAccountDestroy(root_account);
 }
diff --git a/libgnucash/engine/Account.h b/libgnucash/engine/Account.h
index 7c93259..2f80632 100644
--- a/libgnucash/engine/Account.h
+++ b/libgnucash/engine/Account.h
@@ -1454,10 +1454,6 @@ void gnc_account_delete_map_entry (Account *acc, char *full_category, gboolean e
  */
 void gnc_account_imap_convert_bayes (QofBook *book);
 
-/** Change the bayes imap entries from a nested representation to a flat representation.
- */
-void gnc_account_imap_convert_flat (QofBook *);
-
 /** @} */
 
 
diff --git a/libgnucash/engine/kvp-frame.cpp b/libgnucash/engine/kvp-frame.cpp
index 9461d01..29fe927 100644
--- a/libgnucash/engine/kvp-frame.cpp
+++ b/libgnucash/engine/kvp-frame.cpp
@@ -38,6 +38,7 @@ extern "C"
 #include <sstream>
 #include <algorithm>
 #include <vector>
+#include <numeric>
 
 /* This static indicates the debugging module that this .o belongs to.  */
 static QofLogModule log_module = "qof.kvp";
@@ -473,7 +474,7 @@ gnc_value_list_get_type (void)
 }
 
 void
-KvpFrame::flatten_kvp_impl(std::vector<std::string> path, std::vector<std::pair<std::string, KvpValue*>> & entries) const
+KvpFrame::flatten_kvp_impl(std::vector <std::string> path, std::vector <std::pair <std::vector <std::string>, KvpValue*>> & entries) const
 {
     for (auto const & entry : m_valuemap)
     {
@@ -486,16 +487,17 @@ KvpFrame::flatten_kvp_impl(std::vector<std::string> path, std::vector<std::pair<
         }
         else
         {
-            std::string flat_path {std::accumulate(path.begin(), path.end(), std::string{})};
-            entries.emplace_back(flat_path + "/" + entry.first, entry.second);
+            std::vector <std::string> new_path {path};
+            new_path.emplace_back (entry.first);
+            entries.emplace_back (new_path, entry.second);
         }
     }
 }
 
-std::vector<std::pair<std::string, KvpValue*>>
+std::vector <std::pair <std::vector <std::string>, KvpValue*>>
 KvpFrame::flatten_kvp(void) const
 {
-    std::vector<std::pair<std::string, KvpValue*>> ret;
+    std::vector <std::pair <std::vector <std::string>, KvpValue*>> ret;
     flatten_kvp_impl({}, ret);
     return ret;
 }
diff --git a/libgnucash/engine/kvp-frame.hpp b/libgnucash/engine/kvp-frame.hpp
index 0cc206e..49572b8 100644
--- a/libgnucash/engine/kvp-frame.hpp
+++ b/libgnucash/engine/kvp-frame.hpp
@@ -213,6 +213,10 @@ struct KvpFrameImpl
      */
     KvpValue* get_slot(Path keys) const noexcept;
 
+    /**
+     * proc is called with each of the immediate contents of this frame, passing it the key,
+     * value, and specified data.
+     */
     void for_each_slot(void (*proc)(const char *key, KvpValue *, void *data), void* data) const noexcept;
 
     /** The function should be of the form:
@@ -239,7 +243,7 @@ struct KvpFrameImpl
      * Returns all keys and values of this frame recursively, flattening
      * the frame-containing values.
      */
-    std::vector<std::pair<std::string, KvpValue*>>
+    std::vector <std::pair <std::vector <std::string>, KvpValue*>>
     flatten_kvp(void) const;
 
     /** Test for emptiness
@@ -251,7 +255,7 @@ struct KvpFrameImpl
     private:
     map_type m_valuemap;
 
-    void flatten_kvp_impl(std::vector<std::string>, std::vector<std::pair<std::string, KvpValue*>> &) const;
+    void flatten_kvp_impl(std::vector <std::string>, std::vector <std::pair <std::vector <std::string>, KvpValue*>> &) const;
 };
 
 template<typename func_type>
diff --git a/libgnucash/engine/test/gtest-import-map.cpp b/libgnucash/engine/test/gtest-import-map.cpp
index 5938f40..117fe59 100644
--- a/libgnucash/engine/test/gtest-import-map.cpp
+++ b/libgnucash/engine/test/gtest-import-map.cpp
@@ -318,7 +318,6 @@ TEST_F(ImapBayesTest, AddAccountBayes)
     EXPECT_EQ(2, value->get<int64_t>());
 }
 
-
 TEST_F(ImapBayesTest, ConvertAccountBayes)
 {
     // prevent the embedded beginedit/committedit from doing anything
@@ -326,18 +325,15 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
     qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
     gnc_account_imap_add_account_bayes(t_imap, t_list1, t_expense_account1); //Food
     gnc_account_imap_add_account_bayes(t_imap, t_list2, t_expense_account2); //Drink
-
     auto root = qof_instance_get_slots(QOF_INSTANCE(t_bank_account));
     auto book = qof_instance_get_slots(QOF_INSTANCE(t_imap->book));
     auto acct1_guid = guid_to_string (xaccAccountGetGUID(t_expense_account1)); //Food
     auto acct2_guid = guid_to_string (xaccAccountGetGUID(t_expense_account2)); //Drink
     auto acct3_guid = guid_to_string (xaccAccountGetGUID(t_asset_account2)); //Asset-Bank
     auto acct4_guid = guid_to_string (xaccAccountGetGUID(t_sav_account)); //Sav Bank
-
     auto val1 = new KvpValue(static_cast<int64_t>(10));
     auto val2 = new KvpValue(static_cast<int64_t>(5));
     auto val3 = new KvpValue(static_cast<int64_t>(2));
-
     // Test for existing entries, all will be 1
     auto value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
@@ -347,84 +343,36 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
     EXPECT_EQ(1, value->get<int64_t>());
     value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
-
     // Set up some old entries
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + pepper + "/" + "Asset-Bank").c_str(), val1);
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "/token/with/slashes/" + "Asset-Bank").c_str(), val1);
     root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + "Asset-Bank#Bank").c_str(), new KvpValue{*val1});
     root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + "Asset>Bank#Bank").c_str(), val2);
     root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + pork + "/" + "Expense#Food").c_str(), new KvpValue{*val2});
     root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + sausage + "/" + "Expense#Drink").c_str(), val3);
     root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + "Expense#Food").c_str(), new KvpValue{*val2});
-
     EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account)));
     EXPECT_TRUE(qof_instance_get_dirty_flag(QOF_INSTANCE(t_bank_account)));
     qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
-
     // Start Convert
     gnc_account_imap_convert_bayes (t_imap->book);
-
     // convert from 'Asset-Bank' to 'Asset-Bank' guid
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct3_guid).c_str());
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-token-with-slashes-" + acct3_guid).c_str());
     EXPECT_EQ(10, value->get<int64_t>());
-
     // convert from 'Asset-Bank#Bank' to 'Sav Bank' guid
     value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct4_guid).c_str());
     EXPECT_EQ(10, value->get<int64_t>());
-
     // convert from 'Expense#Food' to 'Food' guid
     value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + pork + "-" + acct1_guid).c_str());
     EXPECT_EQ(5, value->get<int64_t>());
-
     // convert from 'Expense#Drink' to 'Drink' guid
     value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + sausage + "-" + acct2_guid).c_str());
     EXPECT_EQ(2, value->get<int64_t>());
-
     // convert from 'Expense#Food' to 'Food' guid but add to original value
     value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid).c_str());
     EXPECT_EQ(5, value->get<int64_t>());
-
     // Check for run once flag
     auto vals = book->get_slot("changed-bayesian-to-guid");
     EXPECT_STREQ("true", vals->get<const char*>());
-
-    EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account)));
-    EXPECT_TRUE(qof_instance_get_dirty_flag(QOF_INSTANCE(t_bank_account)));
-}
-
-TEST_F (ImapBayesTest, convert_map_flat)
-{
-    // prevent the embedded beginedit/committedit from doing anything
-    qof_instance_increase_editlevel(QOF_INSTANCE(t_bank_account));
-    qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
-    //gnc_account_imap_add_account_bayes(t_imap, t_list1, t_expense_account1); //Food
-    //gnc_account_imap_add_account_bayes(t_imap, t_list2, t_expense_account2); //Drink
-    auto root = qof_instance_get_slots(QOF_INSTANCE(t_bank_account));
-    auto acct1_guid = guid_to_string (xaccAccountGetGUID(t_expense_account1)); //Food
-    auto acct2_guid = guid_to_string (xaccAccountGetGUID(t_expense_account2)); //Drink
-    auto acct3_guid = guid_to_string (xaccAccountGetGUID(t_asset_account2)); //Asset-Bank
-    auto acct4_guid = guid_to_string (xaccAccountGetGUID(t_sav_account)); //Sav Bank
-    auto val1 = new KvpValue(static_cast<int64_t>(10));
-    auto val2 = new KvpValue(static_cast<int64_t>(5));
-    auto val3 = new KvpValue(static_cast<int64_t>(2));
-    // Set up some old entries
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + pepper + "/" + acct1_guid).c_str(), val1);
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + acct2_guid).c_str(), new KvpValue{*val1});
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + acct3_guid).c_str(), val2);
-    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + pork + "/" + acct4_guid).c_str(), val3);
-    EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account)));
-    qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
-    gnc_account_imap_convert_flat (t_imap->book);
-    auto value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct1_guid).c_str());
-    EXPECT_EQ(10, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct2_guid).c_str());
-    EXPECT_EQ(10, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct3_guid).c_str());
-    EXPECT_EQ(5, value->get<int64_t>());
-    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + pork + "-" + acct4_guid).c_str());
-    EXPECT_EQ(2, value->get<int64_t>());
-    auto book = qof_instance_get_slots(QOF_INSTANCE(t_imap->book));
-    auto vals = book->get_slot("changed-bayesian-to-flat");
-    EXPECT_STREQ("true", vals->get<const char*>());
     EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account)));
     EXPECT_TRUE(qof_instance_get_dirty_flag(QOF_INSTANCE(t_bank_account)));
 }

commit b3667c76fcca6f374b0e7a52da1023e39713c5da
Author: lmat <dartme18 at gmail.com>
Date:   Thu Oct 19 15:42:32 2017 -0400

    Implement flat bayes kvp
    
    The bayes data are stored in the KVP store. Before this commit, they are
    stored under /import-map-bayes/<token>/<account guid>/count (where count
    is the datum that "matters" in bayes matching).
    
    The problem with this is that any token including the kvp delimiter
    (currently '/') gets divided, and is not found correctly during bayes
    kvp searching. The quickest solution to this is to replace all "/"
    characters with some other character. That has been done, along with a
    re-structuring of the bayes matching code to take advantage of c++
    features to make the code more concise and readable.
    
    Also modified some test functions to fix leaks and double-frees: the
    same kvp value can't be in the kvp tree twice.
    
    Also, when I added code to clean up after the tests, some things started
    breaking due to double-delete. Apparently const_cast was hiding some
    programming errors. Really? You don't say? When giving a GUID* to KvpValue,
    the latter takes ownership of the former.

diff --git a/gnucash/gnome-utils/gnc-file.c b/gnucash/gnome-utils/gnc-file.c
index 12d5e59..96821e5 100644
--- a/gnucash/gnome-utils/gnc-file.c
+++ b/gnucash/gnome-utils/gnc-file.c
@@ -1026,6 +1026,7 @@ RESTART:
     // Convert imap mappings from account full name to guid strings
     qof_event_suspend();
     gnc_account_imap_convert_bayes (gnc_get_current_book());
+    gnc_account_imap_convert_flat (gnc_get_current_book());
     qof_event_resume();
 
     return TRUE;
diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp
index 1b32f9d..a3603e9 100644
--- a/libgnucash/engine/Account.cpp
+++ b/libgnucash/engine/Account.cpp
@@ -41,6 +41,7 @@
 #include "gnc-pricedb.h"
 #include "qofinstance-p.h"
 #include "gnc-features.h"
+#include "guid.hpp"
 
 static QofLogModule log_module = GNC_MOD_ACCOUNT;
 
@@ -5181,48 +5182,6 @@ gnc_account_imap_delete_account (GncImportMatchMap *imap,
 --------------------------------------------------------------------------*/
 
 
-struct account_token_count
-{
-    char* account_guid;
-    gint64 token_count; /**< occurrences of a given token for this account_guid */
-};
-
-/** total_count and the token_count for a given account let us calculate the
- * probability of a given account with any single token
- */
-struct token_accounts_info
-{
-    GList *accounts; /**< array of struct account_token_count */
-    gint64 total_count;
-};
-
-/** gpointer is a pointer to a struct token_accounts_info
- * \note Can always assume that keys are unique, reduces code in this function
- */
-static void
-buildTokenInfo(const char *key, const GValue *value, gpointer data)
-{
-    struct token_accounts_info *tokenInfo = (struct token_accounts_info*)data;
-    struct account_token_count* this_account;
-
-    //  PINFO("buildTokenInfo: account '%s', token_count: '%" G_GINT64_FORMAT "'", (char*)key,
-    //                  g_value_get_int64(value));
-
-    /* add the count to the total_count */
-    tokenInfo->total_count += g_value_get_int64(value);
-
-    /* allocate a new structure for this account and it's token count */
-    this_account = (struct account_token_count*)
-                   g_new0(struct account_token_count, 1);
-
-    /* fill in the account guid and number of tokens found for this account guid */
-    this_account->account_guid = (char*)key;
-    this_account->token_count = g_value_get_int64(value);
-
-    /* append onto the glist a pointer to the new account_token_count structure */
-    tokenInfo->accounts = g_list_prepend(tokenInfo->accounts, this_account);
-}
-
 /** intermediate values used to calculate the bayes probability of a given account
   where p(AB) = (a*b)/[a*b + (1-a)(1-b)], product is (a*b),
   product_difference is (1-a) * (1-b)
@@ -5233,245 +5192,144 @@ struct account_probability
     double product_difference; /* product of (1-probabilities) */
 };
 
-/** convert a hash table of account names and (struct account_probability*)
-  into a hash table of 100000x the percentage match value, ie. 10% would be
-  0.10 * 100000 = 10000
- */
-#define PROBABILITY_FACTOR 100000
-static void
-buildProbabilities(gpointer key, gpointer value, gpointer data)
+struct account_token_count
 {
-    GHashTable *final_probabilities = (GHashTable*)data;
-    struct account_probability *account_p = (struct account_probability*)value;
-
-    /* P(AB) = A*B / [A*B + (1-A)*(1-B)]
-     * NOTE: so we only keep track of a running product(A*B*C...)
-     * and product difference ((1-A)(1-B)...)
-     */
-    gint32 probability =
-        (account_p->product /
-         (account_p->product + account_p->product_difference))
-        * PROBABILITY_FACTOR;
-
-    PINFO("P('%s') = '%d'", (char*)key, probability);
-
-    g_hash_table_insert(final_probabilities, key, GINT_TO_POINTER(probability));
-}
+    std::string account_guid;
+    int64_t token_count; /** occurrences of a given token for this account_guid */
+};
 
-/** Frees an array of the same time that buildProperties built */
-static void
-freeProbabilities(gpointer key, gpointer value, gpointer data)
+/** total_count and the token_count for a given account let us calculate the
+ * probability of a given account with any single token
+ */
+struct token_accounts_info
 {
-    /* free up the struct account_probability that was allocated
-     * in gnc_account_find_account_bayes()
-     */
-    g_free(value);
-}
+    std::vector<account_token_count> accounts;
+    int64_t total_count;
+};
 
 /** holds an account guid and its corresponding integer probability
   the integer probability is some factor of 10
  */
 struct account_info
 {
-    char* account_guid;
-    gint32 probability;
+    std::string account_guid;
+    int32_t probability;
 };
 
-/** Find the highest probability and the corresponding account guid
-    store in data, a (struct account_info*)
-    NOTE: this is a g_hash_table_foreach() function for a hash table of entries
-    key is a  pointer to the account guid, value is a gint32, 100000x
-    the probability for this account
-*/
 static void
-highestProbability(gpointer key, gpointer value, gpointer data)
+build_token_info(char const * key, KvpValue * value, token_accounts_info & tokenInfo)
 {
-    struct account_info *account_i = (struct account_info*)data;
-
-    /* if the current probability is greater than the stored, store the current */
-    if (GPOINTER_TO_INT(value) > account_i->probability)
-    {
-        /* Save the new highest probability and the assoaciated account guid */
-        account_i->probability = GPOINTER_TO_INT(value);
-        account_i->account_guid = static_cast <char*> (key);
-    }
+    tokenInfo.total_count += value->get<int64_t>();
+    account_token_count this_account;
+    std::string account_guid {key};
+    /*By convention, the key ends with the account GUID.*/
+    this_account.account_guid = account_guid.substr(account_guid.size() - GUID_ENCODING_LENGTH);
+    this_account.token_count = value->get<int64_t>();
+    tokenInfo.accounts.push_back(this_account);
 }
 
+/** We scale the probability values by PROBABILITY_FACTOR.
+  ie. with PROBABILITY_FACTOR of 100000, 10% would be
+  0.10 * 100000 = 10000 */
+#define PROBABILITY_FACTOR 100000
 
-#define threshold (.90 * PROBABILITY_FACTOR) /* 90% */
-
-/** Look up an Account in the map */
-Account*
-gnc_account_imap_find_account_bayes (GncImportMatchMap *imap, GList *tokens)
+static std::vector<std::pair<std::string, int32_t>>
+build_probabilities(std::vector<std::pair<std::string, account_probability>> const & first_pass)
 {
-    struct token_accounts_info tokenInfo; /**< holds the accounts and total
-                                           * token count for a single token */
-    GList *current_token;                 /**< pointer to the current
-                                           * token from the input GList
-                                           * tokens */
-    GList *current_account_token;         /**< pointer to the struct
-                                           * account_token_count */
-    struct account_token_count *account_c; /**< an account name and the number
-                                            * of times a token has appeared
-                                            * for the account */
-    struct account_probability *account_p; /**< intermediate storage of values
-                                            * to compute the bayes probability
-                                            * of an account */
-    GHashTable *running_probabilities = g_hash_table_new(g_str_hash,
-                                                         g_str_equal);
-    GHashTable *final_probabilities = g_hash_table_new(g_str_hash,
-                                                       g_str_equal);
-    struct account_info account_i;
-
-    ENTER(" ");
-
-    /* check to see if the imap is NULL */
-    if (!imap)
+    std::vector<std::pair<std::string, int32_t>> ret;
+    for (auto const & first_pass_prob : first_pass)
     {
-        PINFO("imap is null, returning null");
-        LEAVE(" ");
-        return NULL;
+        auto const & account_probability = first_pass_prob.second;
+        /* P(AB) = A*B / [A*B + (1-A)*(1-B)]
+         * NOTE: so we only keep track of a running product(A*B*C...)
+         * and product difference ((1-A)(1-B)...)
+         */
+        int32_t probability = (account_probability.product /
+                (account_probability.product + account_probability.product_difference)) * PROBABILITY_FACTOR;
+        ret.push_back({first_pass_prob.first, probability});
     }
+    return ret;
+}
+
+static account_info
+highest_probability(std::vector<std::pair<std::string, int32_t>> const & probabilities)
+{
+    account_info ret {"", std::numeric_limits<int32_t>::min()};
+    for (auto const & prob : probabilities)
+        if (prob.second > ret.probability)
+            ret = account_info{prob.first, prob.second};
+    return ret;
+}
 
+static std::vector<std::pair<std::string, account_probability>>
+get_first_pass_probabilities(GncImportMatchMap * imap, GList * tokens)
+{
+    std::vector<std::pair<std::string, account_probability>> ret;
     /* find the probability for each account that contains any of the tokens
-     * in the input tokens list
-     */
-    for (current_token = tokens; current_token;
-         current_token = current_token->next)
+     * in the input tokens list. */
+    for (auto current_token = tokens; current_token; current_token = current_token->next)
     {
-        char* path = g_strdup_printf (IMAP_FRAME_BAYES "/%s",
-                                            (char*)current_token->data);
-        /* zero out the token_accounts_info structure */
-        memset(&tokenInfo, 0, sizeof(struct token_accounts_info));
-
-        PINFO("token: '%s'", (char*)current_token->data);
-
-        /* process the accounts for this token, adding the account if it
-         * doesn't already exist or adding to the existing accounts token
-         * count if it does
-         */
-        qof_instance_foreach_slot(QOF_INSTANCE (imap->acc), path,
-                                  buildTokenInfo, &tokenInfo);
-        g_free (path);
-        /* for each account we have just found, see if the account
-         * already exists in the list of account probabilities, if not
-         * add it
-         */
-        for (current_account_token = tokenInfo.accounts; current_account_token;
-                current_account_token = current_account_token->next)
+        auto translated_token = std::string{static_cast<char const *>(current_token->data)};
+        std::replace(translated_token.begin(), translated_token.end(), '/', '-');
+        token_accounts_info tokenInfo{};
+        auto path = std::string{IMAP_FRAME_BAYES "-"} + translated_token;
+        qof_instance_foreach_slot_prefix (QOF_INSTANCE (imap->acc), path, &build_token_info, tokenInfo);
+        for (auto const & current_account_token : tokenInfo.accounts)
         {
-            /* get the account name and corresponding token count */
-            account_c = (struct account_token_count*)current_account_token->data;
-
-            PINFO("account_c->account_guid('%s'), "
-                  "account_c->token_count('%" G_GINT64_FORMAT
-                  "')/total_count('%" G_GINT64_FORMAT "')",
-                  account_c->account_guid, account_c->token_count,
-                  tokenInfo.total_count);
-
-            account_p = static_cast <account_probability*> (
-                    g_hash_table_lookup(running_probabilities, account_c->account_guid));
-
-            /* if the account exists in the list then continue
-             * the running probablities
-             */
-            if (account_p)
-            {
-                account_p->product = (((double)account_c->token_count /
-                                      (double)tokenInfo.total_count)
-                                      * account_p->product);
-                account_p->product_difference =
-                    ((double)1 - ((double)account_c->token_count /
-                                  (double)tokenInfo.total_count))
-                    * account_p->product_difference;
-                PINFO("product == %f, product_difference == %f",
-                      account_p->product, account_p->product_difference);
+            auto item = std::find_if(ret.begin(), ret.end(), [&current_account_token]
+                (std::pair<std::string, account_probability> const & a) {
+                    return current_account_token.account_guid == a.first;
+                });
+            if (item != ret.end())
+            {/* This account is already in the map */
+                item->second.product = ((double)current_account_token.token_count /
+                                      (double)tokenInfo.total_count) * item->second.product;
+                item->second.product_difference = ((double)1 - ((double)current_account_token.token_count /
+                                              (double)tokenInfo.total_count)) * item->second.product_difference;
             }
             else
             {
                 /* add a new entry */
-                PINFO("adding a new entry for this account");
-                account_p = (struct account_probability*)
-                            g_new0(struct account_probability, 1);
-
-                /* set the product and product difference values */
-                account_p->product = ((double)account_c->token_count /
+                account_probability new_probability;
+                new_probability.product = ((double)current_account_token.token_count /
                                       (double)tokenInfo.total_count);
-                account_p->product_difference =
-                    (double)1 - ((double)account_c->token_count /
-                                 (double)tokenInfo.total_count);
-
-                PINFO("product == %f, product_difference == %f",
-                      account_p->product, account_p->product_difference);
-
-                /* add the account guid and (struct account_probability*)
-                 * to the hash table */
-                g_hash_table_insert(running_probabilities,
-                                    account_c->account_guid, account_p);
+                new_probability.product_difference = 1 - (new_probability.product);
+                ret.push_back({current_account_token.account_guid, std::move(new_probability)});
             }
         } /* for all accounts in tokenInfo */
-
-        /* free the data in tokenInfo */
-        for (current_account_token = tokenInfo.accounts; current_account_token;
-                current_account_token = current_account_token->next)
-        {
-            /* free up each struct account_token_count we allocated */
-            g_free((struct account_token_count*)current_account_token->data);
-        }
-
-        g_list_free(tokenInfo.accounts); /* free the accounts GList */
     }
+    return ret;
+}
 
-    /* build a hash table of account names and their final probabilities
-     * from each entry in the running_probabilties hash table
-     */
-    g_hash_table_foreach(running_probabilities, buildProbabilities,
-                         final_probabilities);
-
-    /* find the highest probabilty and the corresponding account */
-    memset(&account_i, 0, sizeof(struct account_info));
-    g_hash_table_foreach(final_probabilities, highestProbability, &account_i);
-
-    /* free each element of the running_probabilities hash */
-    g_hash_table_foreach(running_probabilities, freeProbabilities, NULL);
-
-    /* free the hash tables */
-    g_hash_table_destroy(running_probabilities);
-    g_hash_table_destroy(final_probabilities);
-
-    PINFO("highest P('%s') = '%d'",
-          account_i.account_guid ? account_i.account_guid : "(null)",
-          account_i.probability);
-
-    /* has this probability met our threshold? */
-    if (account_i.probability >= threshold)
-    {
-        GncGUID *guid;
-        Account *account = NULL;
-
-        PINFO("Probability has met threshold");
-
-        guid = g_new (GncGUID, 1);
-
-        if (string_to_guid (account_i.account_guid, guid))
-            account = xaccAccountLookup (guid, imap->book);
-
-        g_free (guid);
-
-        if (account != NULL)
-            LEAVE("Return account is '%s'", xaccAccountGetName (account));
-        else
-            LEAVE("Return NULL, account for Guid '%s' can not be found", account_i.account_guid);
+#define threshold (.90 * PROBABILITY_FACTOR) /* 90% */
 
-        return account;
+/** Look up an Account in the map */
+Account*
+gnc_account_imap_find_account_bayes (GncImportMatchMap *imap, GList *tokens)
+{
+    if (!imap)
+        return nullptr;
+    auto first_pass = get_first_pass_probabilities(imap, tokens);
+    if (!first_pass.size())
+        return nullptr;
+    auto final_probabilities = build_probabilities(first_pass);
+    if (!final_probabilities.size())
+        return nullptr;
+    auto best = highest_probability(final_probabilities);
+    if (best.account_guid == "")
+        return nullptr;
+    if (best.probability < threshold)
+        return nullptr;
+    gnc::GUID guid;
+    try {
+        guid = gnc::GUID::from_string(best.account_guid);
+    } catch (gnc::guid_syntax_exception) {
+        return nullptr;
     }
-    PINFO("Probability has not met threshold");
-    LEAVE("Return NULL");
-
-    return NULL; /* we didn't meet our threshold, return NULL for an account */
+    auto account = xaccAccountLookup (reinterpret_cast<GncGUID*>(&guid), imap->book);
+    return account;
 }
 
-
 static void
 change_imap_entry (GncImportMatchMap *imap, gchar *kvp_path, int64_t token_count)
 {
@@ -5553,13 +5411,13 @@ gnc_account_imap_add_account_bayes (GncImportMatchMap *imap,
 
         PINFO("adding token '%s'", (char*)current_token->data);
 
-        kvp_path = g_strdup_printf (IMAP_FRAME_BAYES "/%s/%s",
-                                    (char*)current_token->data,
+        std::string translated_token {static_cast<char*>(current_token->data)};
+        std::replace(translated_token.begin(), translated_token.end(), '/', '-');
+        kvp_path = g_strdup_printf (IMAP_FRAME_BAYES "-%s-%s",
+                                    translated_token.c_str(),
                                     guid_string);
-
         /* change the imap entry for the account */
         change_imap_entry (imap, kvp_path, token_count);
-
         g_free (kvp_path);
     }
 
@@ -5575,13 +5433,15 @@ gnc_account_imap_add_account_bayes (GncImportMatchMap *imap,
 /*******************************************************************************/
 
 static void
-build_bayes_layer_two (const char *key, const GValue *value, gpointer user_data)
+build_non_bayes (const char *key, const GValue *value, gpointer user_data)
 {
+    if (!G_VALUE_HOLDS_BOXED (value))
+        return;
+
     QofBook     *book;
-    Account     *map_account = NULL;
-    GncGUID     *guid;
+    GncGUID     *guid = NULL;
     gchar       *kvp_path;
-    gchar       *count;
+    gchar       *guid_string = NULL;
 
     struct imap_info *imapInfo_node;
 
@@ -5590,134 +5450,94 @@ build_bayes_layer_two (const char *key, const GValue *value, gpointer user_data)
     // Get the book
     book = qof_instance_get_book (imapInfo->source_account);
 
-    if (G_VALUE_HOLDS_INT64 (value))
-    {
-        PINFO("build_bayes_layer_two: account '%s', token_count: '%" G_GINT64_FORMAT "'",
-                                  (char*)key, g_value_get_int64(value));
+    guid = (GncGUID*)g_value_get_boxed (value);
+    guid_string = guid_to_string (guid);
 
-        count = g_strdup_printf ("%" G_GINT64_FORMAT, g_value_get_int64 (value));
-    }
-    else
-        count = g_strdup ("0");
+    PINFO("build_non_bayes: account '%s', match account guid: '%s'",
+                            (char*)key, guid_string);
 
     kvp_path = g_strconcat (imapInfo->category_head, "/", key, NULL);
 
-    PINFO("build_bayes_layer_two: kvp_path is '%s'", kvp_path);
-
-    guid = g_new (GncGUID, 1);
-
-    if (string_to_guid (key, guid))
-        map_account = xaccAccountLookup (guid, book);
-
-    g_free (guid);
+    PINFO("build_non_bayes: kvp_path is '%s'", kvp_path);
 
     imapInfo_node = static_cast <imap_info*> (g_malloc(sizeof(*imapInfo_node)));
 
     imapInfo_node->source_account = imapInfo->source_account;
-    imapInfo_node->map_account    = map_account;
+    imapInfo_node->map_account    = xaccAccountLookup (guid, book);
     imapInfo_node->full_category  = g_strdup (kvp_path);
-    imapInfo_node->match_string   = g_strdup (imapInfo->match_string);
+    imapInfo_node->match_string   = g_strdup (key);
     imapInfo_node->category_head  = g_strdup (imapInfo->category_head);
-    imapInfo_node->count          = g_strdup (count);
+    imapInfo_node->count          = g_strdup (" ");
 
     imapInfo->list = g_list_append (imapInfo->list, imapInfo_node);
 
     g_free (kvp_path);
-    g_free (count);
+    g_free (guid_string);
 }
 
 static void
-build_bayes (const char *key, const GValue *value, gpointer user_data)
+build_bayes_layer_two (const char *key, KvpValue * val, imap_info imapInfo)
 {
-    gchar *kvp_path;
-    struct imap_info *imapInfo = (struct imap_info*)user_data;
-    struct imap_info  imapInfol2;
-
-    PINFO("build_bayes: match string '%s'", (char*)key);
-
-    if (G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value) == NULL)
+    QofBook     *book;
+    Account     *map_account = NULL;
+    GncGUID     *guid;
+    gchar       *kvp_path;
+    gchar       *count;
+    struct imap_info *imapInfo_node;
+    // Get the book
+    book = qof_instance_get_book (imapInfo.source_account);
+    if (val->get_type() == KvpValue::Type::INT64)
     {
-        kvp_path = g_strdup_printf (IMAP_FRAME_BAYES "/%s", key);
-
-        if (qof_instance_has_slot (QOF_INSTANCE(imapInfo->source_account), kvp_path))
-        {
-            PINFO("build_bayes: kvp_path is '%s', key '%s'", kvp_path, key);
-
-            imapInfol2.source_account = imapInfo->source_account;
-            imapInfol2.match_string   = g_strdup (key);
-            imapInfol2.category_head  = g_strdup (kvp_path);
-            imapInfol2.list           = imapInfo->list;
-
-            qof_instance_foreach_slot (QOF_INSTANCE(imapInfo->source_account), kvp_path,
-                                       build_bayes_layer_two, &imapInfol2);
-
-            imapInfo->list = imapInfol2.list;
-            g_free (imapInfol2.match_string);
-            g_free (imapInfol2.category_head);
-        }
-        g_free (kvp_path);
+        PINFO("build_bayes_layer_two: account '%s', token_count: '%" G_GINT64_FORMAT "'",
+                                  key, val->get<int64_t>());
+        count = g_strdup_printf ("%" G_GINT64_FORMAT, val->get<int64_t>());
     }
+    else
+        count = g_strdup ("0");
+    kvp_path = g_strconcat (imapInfo.category_head, "/", key, NULL);
+    PINFO("build_bayes_layer_two: kvp_path is '%s'", kvp_path);
+    guid = g_new (GncGUID, 1);
+    if (string_to_guid (key, guid))
+        map_account = xaccAccountLookup (guid, book);
+    g_free (guid);
+    imapInfo_node = static_cast <imap_info*> (g_malloc(sizeof(*imapInfo_node)));
+    imapInfo_node->source_account = imapInfo.source_account;
+    imapInfo_node->map_account    = map_account;
+    imapInfo_node->full_category  = g_strdup (kvp_path);
+    imapInfo_node->match_string   = g_strdup (imapInfo.match_string);
+    imapInfo_node->category_head  = g_strdup (imapInfo.category_head);
+    imapInfo_node->count          = g_strdup (count);
+    imapInfo.list = g_list_append (imapInfo.list, imapInfo_node);
+    g_free (kvp_path);
+    g_free (count);
 }
 
-
 static void
-build_non_bayes (const char *key, const GValue *value, gpointer user_data)
+build_bayes (const char *key, KvpValue * value, imap_info & imapInfo)
 {
-    if (G_VALUE_HOLDS_BOXED (value))
-    {
-        QofBook     *book;
-        GncGUID     *guid = NULL;
-        gchar       *kvp_path;
-        gchar       *guid_string = NULL;
-
-        struct imap_info *imapInfo_node;
-
-        struct imap_info *imapInfo = (struct imap_info*)user_data;
-
-        // Get the book
-        book = qof_instance_get_book (imapInfo->source_account);
-
-        guid = (GncGUID*)g_value_get_boxed (value);
-        guid_string = guid_to_string (guid);
-
-        PINFO("build_non_bayes: account '%s', match account guid: '%s'",
-                                (char*)key, guid_string);
-
-        kvp_path = g_strconcat (imapInfo->category_head, "/", key, NULL);
-
-        PINFO("build_non_bayes: kvp_path is '%s'", kvp_path);
-
-        imapInfo_node = static_cast <imap_info*> (g_malloc(sizeof(*imapInfo_node)));
-
-        imapInfo_node->source_account = imapInfo->source_account;
-        imapInfo_node->map_account    = xaccAccountLookup (guid, book);
-        imapInfo_node->full_category  = g_strdup (kvp_path);
-        imapInfo_node->match_string   = g_strdup (key);
-        imapInfo_node->category_head  = g_strdup (imapInfo->category_head);
-        imapInfo_node->count          = g_strdup (" ");
-
-        imapInfo->list = g_list_append (imapInfo->list, imapInfo_node);
+    struct imap_info imapInfol2;
+    PINFO("build_bayes: match string '%s'", (char*)key);
 
-        g_free (kvp_path);
-        g_free (guid_string);
-    }
+    std::string prefix {g_strdup_printf (IMAP_FRAME_BAYES "-%s", key)};
+    PINFO("build_bayes: prefix is '%s', key '%s'", prefix.c_str(), key);
+    imapInfol2.source_account = imapInfo.source_account;
+    imapInfol2.match_string   = g_strdup (key);
+    imapInfol2.category_head  = g_strdup (prefix.c_str());
+    imapInfol2.list           = imapInfo.list;
+    qof_instance_foreach_slot_prefix (QOF_INSTANCE(imapInfo.source_account), prefix,
+                               build_bayes_layer_two, imapInfol2);
+    imapInfo.list = imapInfol2.list;
+    g_free (imapInfol2.match_string);
+    g_free (imapInfol2.category_head);
 }
 
-
 GList *
 gnc_account_imap_get_info_bayes (Account *acc)
 {
-    GList *list = NULL;
-
-    GncImapInfo imapInfo;
-
-    imapInfo.source_account = acc;
-    imapInfo.list = list;
-
-    if (qof_instance_has_slot (QOF_INSTANCE(acc), IMAP_FRAME_BAYES))
-        qof_instance_foreach_slot (QOF_INSTANCE(acc), IMAP_FRAME_BAYES,
-                                   build_bayes, &imapInfo);
-
+    /* A dummy object which is used to hold the specified account, and the list
+     * of data about which we care. */
+    GncImapInfo imapInfo {acc, nullptr};
+    qof_instance_foreach_slot_prefix (QOF_INSTANCE (acc), IMAP_FRAME_BAYES, &build_bayes, imapInfo);
     return imapInfo.list;
 }
 
@@ -5774,18 +5594,14 @@ void
 gnc_account_delete_map_entry (Account *acc, char *full_category, gboolean empty)
 {
     gchar *kvp_path = g_strdup (full_category);
-
     if ((acc != NULL) && qof_instance_has_slot (QOF_INSTANCE(acc), kvp_path))
     {
         xaccAccountBeginEdit (acc);
-
         if (empty)
             qof_instance_slot_delete_if_empty (QOF_INSTANCE(acc), kvp_path);
         else
             qof_instance_slot_delete (QOF_INSTANCE(acc), kvp_path);
-
         PINFO("Account is '%s', path is '%s'", xaccAccountGetName (acc), kvp_path);
-
         qof_instance_set_dirty (QOF_INSTANCE(acc));
         xaccAccountCommitEdit (acc);
     }
@@ -5796,11 +5612,12 @@ gnc_account_delete_map_entry (Account *acc, char *full_category, gboolean empty)
 /*******************************************************************************/
 
 static gchar *
-look_for_old_separator_descendants (Account *root, gchar *full_name, const gchar *separator)
+look_for_old_separator_descendants (Account *root, gchar const *full_name, const gchar *separator)
 {
     GList *top_accounts, *ptr;
     gint   found_len = 0;
     gchar  found_sep;
+    gchar * new_name = nullptr;
 
     top_accounts = gnc_account_get_descendants (root);
 
@@ -5828,60 +5645,16 @@ look_for_old_separator_descendants (Account *root, gchar *full_name, const gchar
         }
     }
     g_list_free (top_accounts); // Free the List
+    new_name = g_strdup (full_name);
 
     if (found_len > 1)
-        full_name = g_strdelimit (full_name, &found_sep, *separator);
-
-    PINFO("Return full_name is '%s'", full_name);
-
-    return full_name;
-}
-
-
-static void
-convert_imap_entry (GncImapInfo *imapInfo, Account *map_account)
-{
-    GncImportMatchMap *imap;
-    gchar   *guid_string;
-    gchar   *kvp_path;
-    int64_t  token_count = 1;
-
-    GValue value = G_VALUE_INIT;
-
-    // Create an ImportMatchMap object
-    imap = gnc_account_imap_create_imap (imapInfo->source_account);
-
-    xaccAccountBeginEdit (imapInfo->source_account);
-
-    guid_string = guid_to_string (xaccAccountGetGUID (map_account));
-
-    PINFO("Map Account is '%s', GUID is '%s', Count is %s", xaccAccountGetName (map_account),
-               guid_string, imapInfo->count);
-
-    // save converting string, get the count value
-    qof_instance_get_kvp (QOF_INSTANCE (imapInfo->source_account), imapInfo->full_category, &value);
+        g_strdelimit (new_name, &found_sep, *separator);
 
-    if (G_VALUE_HOLDS_INT64 (&value))
-        token_count = g_value_get_int64 (&value);
+    PINFO("Return full_name is '%s'", new_name);
 
-    // Delete the old entry based on full account name
-    kvp_path = g_strdup (imapInfo->full_category);
-    gnc_account_delete_map_entry (imapInfo->source_account, kvp_path, FALSE);
-
-    // create path based on guid
-    kvp_path = g_strdup_printf ("/%s/%s", imapInfo->category_head, guid_string);
-
-    // change the imap entry of source_account
-    change_imap_entry (imap, kvp_path, token_count);
-
-    qof_instance_set_dirty (QOF_INSTANCE (imapInfo->source_account));
-    xaccAccountCommitEdit (imapInfo->source_account);
-
-    g_free (kvp_path);
-    g_free (guid_string);
+    return new_name;
 }
 
-
 static Account *
 look_for_old_mapping (GncImapInfo *imapInfo)
 {
@@ -5905,7 +5678,9 @@ look_for_old_mapping (GncImapInfo *imapInfo)
     // do we have a valid account, if not, look for old separator
     if (map_account == NULL)
     {
-        full_name = look_for_old_separator_descendants (root, full_name, sep);
+        gchar * temp_name = look_for_old_separator_descendants (root, full_name, sep);
+        g_free(full_name);
+        full_name = temp_name;
         map_account = gnc_account_lookup_by_full_name (root, full_name); // lets try again
     }
 
@@ -5916,84 +5691,150 @@ look_for_old_mapping (GncImapInfo *imapInfo)
     return map_account;
 }
 
+static std::vector<std::pair<std::string, KvpValue*>>
+get_new_guid_imap (Account * acc)
+{
+    auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
+    auto slot = frame->get_slot(IMAP_FRAME_BAYES);
+    if (!slot)
+        return {};
+    std::string const imap_frame_str {IMAP_FRAME_BAYES};
+    std::vector<std::pair<std::string, KvpValue*>> ret;
+    auto root = gnc_account_get_root (acc);
+    auto imap_frame = slot->get<KvpFrame*>();
+    imap_frame->for_each_slot_temp ([&ret, root, &imap_frame_str] (char const * token, KvpValue* val) {
+        auto token_frame = val->get<KvpFrame*>();
+        token_frame->for_each_slot_temp ([&ret, root, &imap_frame_str, token] (char const * account_name, KvpValue* val) {
+            auto map_account = gnc_account_lookup_by_full_name (root, account_name);
+            if (!map_account)
+            {
+                auto temp_account_name = look_for_old_separator_descendants (root, account_name, gnc_get_account_separator_string());
+                map_account = gnc_account_lookup_by_full_name (root, temp_account_name);
+                g_free (temp_account_name);
+            }
+            auto temp_guid = gnc::GUID{*xaccAccountGetGUID (map_account)};
+            auto guid_str = temp_guid.to_string();
+            ret.push_back({imap_frame_str + "-" + token + "-" + guid_str, val});
+        });
+    });
+    return ret;
+}
+
 static void
-convert_imap_account (Account *acc)
+convert_imap_account_bayes_to_guid (Account *acc)
 {
-    GList *imap_list, *node;
-    gchar *acc_name = NULL;
-
-    acc_name = gnc_account_get_full_name (acc);
-    PINFO("Source Acc '%s'", acc_name);
+    auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
+    if (!frame->get_keys().size())
+        return;
+    auto new_imap = get_new_guid_imap(acc);
+    xaccAccountBeginEdit(acc);
+    frame->set(IMAP_FRAME_BAYES, nullptr);
+    std::for_each(new_imap.begin(), new_imap.end(), [&frame] (std::pair<std::string, KvpValue*> const & entry) {
+        frame->set(entry.first.c_str(), entry.second);
+    });
+    qof_instance_set_dirty (QOF_INSTANCE (acc));
+    xaccAccountCommitEdit(acc);
+}
 
-    imap_list = gnc_account_imap_get_info_bayes (acc);
+char const * run_once_key_to_guid {"changed-bayesian-to-guid"};
+char const * run_once_key_to_flat {"changed-bayesian-to-flat"};
 
-    if (g_list_length (imap_list) > 0) // we have mappings
+static void
+imap_convert_bayes_to_guid (QofBook * book)
+{
+    auto root = gnc_book_get_root_account (book);
+    auto accts = gnc_account_get_descendants_sorted (root);
+    for (auto ptr = accts; ptr; ptr = g_list_next (ptr))
     {
-        PINFO("List length is %d", g_list_length (imap_list));
-        xaccAccountBeginEdit(acc);
-        for (node = imap_list;  node; node = g_list_next (node))
-        {
-            Account *map_account = NULL;
-            GncImapInfo *imapInfo = static_cast <GncImapInfo *> (node->data);
-
-            // Lets start doing stuff
-            map_account = look_for_old_mapping (imapInfo);
-
-            if (map_account != NULL) // we have an account, try and update it
-                convert_imap_entry (imapInfo, map_account);
-            // Free the members and structure
-            g_free (imapInfo->category_head);
-            g_free (imapInfo->full_category);
-            g_free (imapInfo->match_string);
-            g_free (imapInfo->count);
-            g_free (imapInfo);
-        }
-        xaccAccountCommitEdit(acc);
+        Account *acc = static_cast <Account*> (ptr->data);
+        convert_imap_account_bayes_to_guid (acc);
     }
-    g_free (acc_name);
-    g_list_free (imap_list); // Free the List
+    g_list_free (accts);
+}
+
+static std::vector<std::pair<std::string, KvpValue*>>
+get_new_flat_imap (Account * acc)
+{
+    auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
+    auto slot = frame->get_slot(IMAP_FRAME_BAYES);
+    if (!slot)
+        return {};
+    std::string const imap_frame_str {IMAP_FRAME_BAYES};
+    std::vector<std::pair<std::string, KvpValue*>> ret;
+    auto root = gnc_account_get_root (acc);
+    auto imap_frame = slot->get<KvpFrame*>();
+    imap_frame->for_each_slot_temp ([&ret, &imap_frame_str] (char const * token, KvpValue* val) {
+        auto token_frame = val->get<KvpFrame*>();
+        token_frame->for_each_slot_temp ([&ret, &imap_frame_str, token] (char const * account_guid, KvpValue* val) {
+            ret.push_back({imap_frame_str + "-" + token + "-" + account_guid, val});
+        });
+    });
+    return ret;
 }
 
-void
-gnc_account_imap_convert_bayes (QofBook *book)
+static void
+convert_imap_account_bayes_to_flat (Account * acc)
 {
-    Account      *root;
-    GList        *accts, *ptr;
-    gboolean      run_once = FALSE;
-    GValue        value_s = G_VALUE_INIT;
-
-    // get the run-once value
-    qof_instance_get_kvp (QOF_INSTANCE (book), "changed-bayesian-to-guid", &value_s);
-
-    if (G_VALUE_HOLDS_STRING (&value_s) && (strcmp(g_value_get_string (&value_s), "true") == 0))
-        run_once = TRUE;
+    auto flat_imap = get_new_flat_imap (acc);
+    if (!flat_imap.size())
+        return;
+    auto frame = qof_instance_get_slots (QOF_INSTANCE (acc));
+    xaccAccountBeginEdit(acc);
+    frame->set(IMAP_FRAME_BAYES, nullptr);
+    std::for_each(flat_imap.begin(), flat_imap.end(), [&frame] (std::pair<std::string, KvpValue*> const & entry) {
+        frame->set(entry.first.c_str(), entry.second);
+    });
+    qof_instance_set_dirty (QOF_INSTANCE (acc));
+    xaccAccountCommitEdit(acc);
+}
 
-    if (run_once == FALSE)
+static void
+imap_convert_bayes_to_flat (QofBook * book)
+{
+    auto root = gnc_book_get_root_account (book);
+    auto accts = gnc_account_get_descendants_sorted (root);
+    for (auto ptr = accts; ptr; ptr = g_list_next (ptr))
     {
-        GValue value_b = G_VALUE_INIT;
-
-        /* Get list of Accounts */
-        root = gnc_book_get_root_account (book);
-        accts = gnc_account_get_descendants_sorted (root);
-
-        /* Go through list of accounts */
-        for (ptr = accts; ptr; ptr = g_list_next (ptr))
-        {
-            Account *acc = static_cast <Account*> (ptr->data);
-
-            convert_imap_account (acc);
-        }
-        g_list_free (accts);
+        Account *acc = static_cast <Account*> (ptr->data);
+        convert_imap_account_bayes_to_flat (acc);
+    }
+    g_list_free (accts);
+}
 
-        g_value_init (&value_b, G_TYPE_BOOLEAN);
+static bool
+run_once_key_set (char const * key, QofBook * book)
+{
+    GValue value G_VALUE_INIT;
+    qof_instance_get_kvp (QOF_INSTANCE(book), key, &value);
+    return G_VALUE_HOLDS_STRING(&value) && strcmp(g_value_get_string(&value), "true");
+}
 
-        g_value_set_boolean (&value_b, TRUE);
+static void
+set_run_once_key (char const * key, QofBook * book)
+{
+    GValue value G_VALUE_INIT;
+    g_value_init(&value, G_TYPE_BOOLEAN);
+    g_value_set_boolean(&value, TRUE);
+    qof_instance_set_kvp(QOF_INSTANCE (book), key, &value);
+}
 
-        // set the run-once value
-        qof_instance_set_kvp (QOF_INSTANCE (book), "changed-bayesian-to-guid", &value_b);
-    }
+void
+gnc_account_imap_convert_flat (QofBook *book)
+{
+    if (run_once_key_set(run_once_key_to_flat, book))
+        return;
+    imap_convert_bayes_to_flat (book);
+    set_run_once_key(run_once_key_to_flat, book);
 }
 
+void
+gnc_account_imap_convert_bayes (QofBook *book)
+{
+    if (run_once_key_set(run_once_key_to_guid, book))
+        return;
+    imap_convert_bayes_to_guid(book);
+    set_run_once_key(run_once_key_to_guid, book);
+}
 
 /* ================================================================ */
 /* QofObject function implementation and registration */
diff --git a/libgnucash/engine/Account.h b/libgnucash/engine/Account.h
index 2f80632..7c93259 100644
--- a/libgnucash/engine/Account.h
+++ b/libgnucash/engine/Account.h
@@ -1454,6 +1454,10 @@ void gnc_account_delete_map_entry (Account *acc, char *full_category, gboolean e
  */
 void gnc_account_imap_convert_bayes (QofBook *book);
 
+/** Change the bayes imap entries from a nested representation to a flat representation.
+ */
+void gnc_account_imap_convert_flat (QofBook *);
+
 /** @} */
 
 
diff --git a/libgnucash/engine/guid.cpp b/libgnucash/engine/guid.cpp
index e939ac8..5706802 100644
--- a/libgnucash/engine/guid.cpp
+++ b/libgnucash/engine/guid.cpp
@@ -356,6 +356,21 @@ GUID::from_string (std::string const & str)
     }
 }
 
+bool
+GUID::is_valid_guid (std::string const & str)
+{
+    try
+    {
+        static boost::uuids::string_generator strgen;
+        auto a = strgen (str);
+        return true;
+    }
+    catch (...)
+    {
+        return false;
+    }
+}
+
 guid_syntax_exception::guid_syntax_exception () noexcept
     : invalid_argument {"Invalid syntax for guid."}
 {
diff --git a/libgnucash/engine/guid.hpp b/libgnucash/engine/guid.hpp
index db6e4dc..837d509 100644
--- a/libgnucash/engine/guid.hpp
+++ b/libgnucash/engine/guid.hpp
@@ -50,6 +50,7 @@ struct GUID
     static GUID create_random () noexcept;
     static GUID const & null_guid () noexcept;
     static GUID from_string (std::string const &);
+    static bool is_valid_guid (std::string const &);
     std::string to_string () const noexcept;
     auto begin () const noexcept -> decltype (implementation.begin ());
     auto end () const noexcept -> decltype (implementation.end ());
diff --git a/libgnucash/engine/kvp-frame.cpp b/libgnucash/engine/kvp-frame.cpp
index 13a0e4e..9461d01 100644
--- a/libgnucash/engine/kvp-frame.cpp
+++ b/libgnucash/engine/kvp-frame.cpp
@@ -472,4 +472,30 @@ gnc_value_list_get_type (void)
     return type;
 }
 
-/* ========================== END OF FILE ======================= */
+void
+KvpFrame::flatten_kvp_impl(std::vector<std::string> path, std::vector<std::pair<std::string, KvpValue*>> & entries) const
+{
+    for (auto const & entry : m_valuemap)
+    {
+        if (entry.second->get_type() == KvpValue::Type::FRAME)
+        {
+            std::vector<std::string> send_path {path};
+            send_path.push_back("/");
+            send_path.push_back(entry.first);
+            entry.second->get<KvpFrame*>()->flatten_kvp_impl(send_path, entries);
+        }
+        else
+        {
+            std::string flat_path {std::accumulate(path.begin(), path.end(), std::string{})};
+            entries.emplace_back(flat_path + "/" + entry.first, entry.second);
+        }
+    }
+}
+
+std::vector<std::pair<std::string, KvpValue*>>
+KvpFrame::flatten_kvp(void) const
+{
+    std::vector<std::pair<std::string, KvpValue*>> ret;
+    flatten_kvp_impl({}, ret);
+    return ret;
+}
diff --git a/libgnucash/engine/kvp-frame.hpp b/libgnucash/engine/kvp-frame.hpp
index 1af4217..0cc206e 100644
--- a/libgnucash/engine/kvp-frame.hpp
+++ b/libgnucash/engine/kvp-frame.hpp
@@ -93,6 +93,8 @@
 #include <string>
 #include <vector>
 #include <cstring>
+#include <algorithm>
+#include <iostream>
 using Path = std::vector<std::string>;
 
 /** Implements KvpFrame.
@@ -192,7 +194,7 @@ struct KvpFrameImpl
      * prefixed to every item in the frame.
      * @return A std::string representing all the children of the frame.
      */
-    std::string to_string(std::string const & prefix) const noexcept;
+    std::string to_string(std::string const &) const noexcept;
     /**
      * Report the keys in the immediate frame. Be sensible about using this, it
      * isn't a very efficient way to iterate.
@@ -211,14 +213,34 @@ struct KvpFrameImpl
      */
     KvpValue* get_slot(Path keys) const noexcept;
 
-    void for_each_slot(void (*)(char const *key, KvpValue*, void*data), void*data) const noexcept;
+    void for_each_slot(void (*proc)(const char *key, KvpValue *, void *data), void* data) const noexcept;
 
     /** The function should be of the form:
      * <anything> func (char const *, KvpValue *, data_type &);
-     * Do not pass nullptr for the function.
+     * Do not pass nullptr as the function.
      */
     template <typename func_type, typename data_type>
-    void for_each_slot_temp (func_type const &, data_type &) const noexcept;
+    void for_each_slot_temp(func_type const &, data_type &) const noexcept;
+
+    template <typename func_type>
+    void for_each_slot_temp(func_type const &) const noexcept;
+
+    /**
+     * Like for_each_slot, but doesn't traverse nested values. This will only loop
+     * over root-level values whose keys match the specified prefix.
+     */
+    template <typename func_type, typename data_type>
+    void for_each_slot_prefix(std::string const & prefix, func_type const &, data_type &) const noexcept;
+
+    template <typename func_type>
+    void for_each_slot_prefix(std::string const & prefix, func_type const &) const noexcept;
+
+    /**
+     * Returns all keys and values of this frame recursively, flattening
+     * the frame-containing values.
+     */
+    std::vector<std::pair<std::string, KvpValue*>>
+    flatten_kvp(void) const;
 
     /** Test for emptiness
      * @return true if the frame contains nothing.
@@ -228,8 +250,55 @@ struct KvpFrameImpl
 
     private:
     map_type m_valuemap;
+
+    void flatten_kvp_impl(std::vector<std::string>, std::vector<std::pair<std::string, KvpValue*>> &) const;
 };
 
+template<typename func_type>
+void KvpFrame::for_each_slot_prefix(std::string const & prefix,
+        func_type const & func) const noexcept
+{
+    std::for_each (m_valuemap.begin(), m_valuemap.end(),
+        [&prefix,&func](const KvpFrameImpl::map_type::value_type & a)
+        {
+            std::string temp_key {a.first};
+            if (temp_key.size() < prefix.size())
+                return;
+            /* Testing for prefix matching */
+            if (std::mismatch(prefix.begin(), prefix.end(), temp_key.begin()).first == prefix.end())
+                func (a.first, a.second);
+        }
+    );
+}
+
+template<typename func_type, typename data_type>
+void KvpFrame::for_each_slot_prefix(std::string const & prefix,
+        func_type const & func, data_type & data) const noexcept
+{
+    std::for_each (m_valuemap.begin(), m_valuemap.end(),
+        [&prefix,&func,&data](const KvpFrameImpl::map_type::value_type & a)
+        {
+            std::string temp_key {a.first};
+            if (temp_key.size() < prefix.size())
+                return;
+            /* Testing for prefix matching */
+            if (std::mismatch(prefix.begin(), prefix.end(), temp_key.begin()).first == prefix.end())
+                func (a.first, a.second, data);
+        }
+    );
+}
+
+template <typename func_type>
+void KvpFrame::for_each_slot_temp(func_type const & func) const noexcept
+{
+    std::for_each (m_valuemap.begin(), m_valuemap.end(),
+        [&func](const KvpFrameImpl::map_type::value_type & a)
+        {
+            func (a.first, a.second);
+        }
+    );
+}
+
 template <typename func_type, typename data_type>
 void KvpFrame::for_each_slot_temp(func_type const & func, data_type & data) const noexcept
 {
@@ -241,7 +310,6 @@ void KvpFrame::for_each_slot_temp(func_type const & func, data_type & data) cons
     );
 }
 
-
 int compare (const KvpFrameImpl &, const KvpFrameImpl &) noexcept;
 int compare (const KvpFrameImpl *, const KvpFrameImpl *) noexcept;
 /** @} Doxygen Group */
diff --git a/libgnucash/engine/qofinstance-p.h b/libgnucash/engine/qofinstance-p.h
index ca6a4c5..5ffcd9f 100644
--- a/libgnucash/engine/qofinstance-p.h
+++ b/libgnucash/engine/qofinstance-p.h
@@ -160,6 +160,10 @@ void qof_instance_foreach_slot (const QofInstance *inst, const char *path,
 #ifdef __cplusplus
 } /* extern "C" */
 
+/** Returns all keys that match the given prefix and their corresponding values.*/
+std::map<std::string, KvpValue*>
+qof_instance_get_slots_prefix (QofInstance const *, std::string const & prefix);
+
 /* Don't pass nullptr as the function */
 template<typename func_type, typename data_type>
 void qof_instance_foreach_slot_temp (QofInstance const * inst, std::string const & path,
@@ -171,6 +175,18 @@ void qof_instance_foreach_slot_temp (QofInstance const * inst, std::string const
     auto frame = slot->get<KvpFrame*>();
     frame->for_each_slot(func, data);
 }
+
+/**
+ * Similar to qof_instance_foreach_slot, but we don't traverse the depth of the key value frame,
+ * we only check the root level for keys that match the specified prefix.
+ */
+template<typename func_type, typename data_type>
+void qof_instance_foreach_slot_prefix(QofInstance const * inst, std::string const & path_prefix,
+        func_type const & func, data_type & data)
+{
+    inst->kvp_data->for_each_slot_prefix(path_prefix, func, data);
+}
+
 #endif
 
 #endif /* QOF_INSTANCE_P_H */
diff --git a/libgnucash/engine/test/gtest-import-map.cpp b/libgnucash/engine/test/gtest-import-map.cpp
index f5f3cf2..5938f40 100644
--- a/libgnucash/engine/test/gtest-import-map.cpp
+++ b/libgnucash/engine/test/gtest-import-map.cpp
@@ -30,6 +30,7 @@ extern "C"
 #include <qofinstance-p.h>
 #include <kvp-frame.hpp>
 #include <gtest/gtest.h>
+#include <string>
 
 class ImapTest : public testing::Test
 {
@@ -67,7 +68,11 @@ protected:
         gnc_account_append_child(t_expense_account, t_expense_account2);
     }
     void TearDown() {
-        qof_book_destroy (gnc_account_get_book (t_bank_account));
+        auto root = gnc_account_get_root (t_bank_account);
+        auto book = gnc_account_get_book (root);
+        xaccAccountBeginEdit (root);
+        xaccAccountDestroy (root);
+        qof_book_destroy (book);
     }
     Account *t_bank_account {};
     Account *t_sav_account {};
@@ -110,18 +115,16 @@ protected:
 TEST_F(ImapPlainTest, FindAccount)
 {
     auto root = qof_instance_get_slots(QOF_INSTANCE(t_bank_account));
-    auto acc1_val = new KvpValue(const_cast<GncGUID*>(xaccAccountGetGUID(t_expense_account1)));
-    auto acc2_val = new KvpValue(const_cast<GncGUID*>(xaccAccountGetGUID(t_expense_account2)));
+    auto acc1_val = new KvpValue(guid_copy(xaccAccountGetGUID(t_expense_account1)));
+    auto acc2_val = new KvpValue(guid_copy(xaccAccountGetGUID(t_expense_account2)));
     root->set_path({IMAP_FRAME, "foo", "bar"}, acc1_val);
     root->set_path({IMAP_FRAME, "baz", "waldo"}, acc2_val);
-    root->set_path({IMAP_FRAME, "pepper"}, acc1_val);
-    root->set_path({IMAP_FRAME, "salt"}, acc2_val);
+    root->set_path({IMAP_FRAME, "pepper"}, new KvpValue{*acc1_val});
+    root->set_path({IMAP_FRAME, "salt"}, new KvpValue{*acc2_val});
 
     EXPECT_EQ(t_expense_account1, gnc_account_imap_find_account(t_imap, "foo", "bar"));
-    EXPECT_EQ(t_expense_account2,
-              gnc_account_imap_find_account(t_imap, "baz", "waldo"));
-    EXPECT_EQ(t_expense_account1,
-              gnc_account_imap_find_account(t_imap, NULL, "pepper"));
+    EXPECT_EQ(t_expense_account2, gnc_account_imap_find_account(t_imap, "baz", "waldo"));
+    EXPECT_EQ(t_expense_account1, gnc_account_imap_find_account(t_imap, NULL, "pepper"));
     EXPECT_EQ(t_expense_account2, gnc_account_imap_find_account(t_imap, NULL, "salt"));
     EXPECT_EQ(nullptr, gnc_account_imap_find_account(t_imap, "salt", NULL));
 }
@@ -251,12 +254,12 @@ TEST_F(ImapBayesTest, FindAccountBayes)
     auto acct2_guid = guid_to_string (xaccAccountGetGUID(t_expense_account2));
     auto value = new KvpValue(INT64_C(42));
 
-    root->set_path({IMAP_FRAME_BAYES, foo, acct1_guid}, value);
-    root->set_path({IMAP_FRAME_BAYES, bar, acct1_guid}, value);
-    root->set_path({IMAP_FRAME_BAYES, baz, acct2_guid}, value);
-    root->set_path({IMAP_FRAME_BAYES, waldo, acct2_guid}, value);
-    root->set_path({IMAP_FRAME_BAYES, pepper, acct1_guid}, value);
-    root->set_path({IMAP_FRAME_BAYES, salt, acct2_guid}, value);
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid).c_str(), value);
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid).c_str(), new KvpValue{*value});
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid).c_str(), new KvpValue{*value});
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid).c_str(), new KvpValue{*value});
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct1_guid).c_str(), new KvpValue{*value});
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct2_guid).c_str(), new KvpValue{*value});
 
     auto account = gnc_account_imap_find_account_bayes(t_imap, t_list1);
     EXPECT_EQ(t_expense_account1, account);
@@ -289,29 +292,29 @@ TEST_F(ImapBayesTest, AddAccountBayes)
     auto root = qof_instance_get_slots(QOF_INSTANCE(t_bank_account));
     auto acct1_guid = guid_to_string (xaccAccountGetGUID(t_expense_account1));
     auto acct2_guid = guid_to_string (xaccAccountGetGUID(t_expense_account2));
-    auto value = root->get_slot({IMAP_FRAME_BAYES, "foo", "bar"});
+    auto value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-foo-bar").c_str());
     auto check_account = [this](KvpValue* v) {
         return (v->get<const char*>(), this->t_imap->book); };
-    value = root->get_slot({IMAP_FRAME_BAYES, foo, acct1_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({IMAP_FRAME_BAYES, bar, acct1_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({IMAP_FRAME_BAYES, baz, acct2_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({IMAP_FRAME_BAYES, waldo, acct2_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({IMAP_FRAME_BAYES, pepper, acct1_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct1_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({IMAP_FRAME_BAYES, salt, acct2_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct2_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({IMAP_FRAME_BAYES, baz, acct1_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct1_guid).c_str());
     EXPECT_EQ(nullptr, value);
 
     qof_instance_increase_editlevel(QOF_INSTANCE(t_bank_account));
     gnc_account_imap_add_account_bayes(t_imap, t_list2, t_expense_account2);
     qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
     qof_instance_reset_editlevel(QOF_INSTANCE(t_bank_account));
-    value = root->get_slot({IMAP_FRAME_BAYES, baz, acct2_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid).c_str());
     EXPECT_EQ(2, value->get<int64_t>());
 }
 
@@ -336,22 +339,22 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
     auto val3 = new KvpValue(static_cast<int64_t>(2));
 
     // Test for existing entries, all will be 1
-    auto value = root->get_slot({IMAP_FRAME_BAYES, foo, acct1_guid});
+    auto value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({IMAP_FRAME_BAYES, bar, acct1_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + bar + "-" + acct1_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({IMAP_FRAME_BAYES, baz, acct2_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + baz + "-" + acct2_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
-    value = root->get_slot({IMAP_FRAME_BAYES, waldo, acct2_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + waldo + "-" + acct2_guid).c_str());
     EXPECT_EQ(1, value->get<int64_t>());
 
     // Set up some old entries
-    root->set_path({IMAP_FRAME_BAYES, pepper, "Asset-Bank"}, val1);
-    root->set_path({IMAP_FRAME_BAYES, salt, "Asset-Bank#Bank"}, val1);
-    root->set_path({IMAP_FRAME_BAYES, salt, "Asset>Bank#Bank"}, val2);
-    root->set_path({IMAP_FRAME_BAYES, pork, "Expense#Food"}, val2);
-    root->set_path({IMAP_FRAME_BAYES, sausage, "Expense#Drink"}, val3);
-    root->set_path({IMAP_FRAME_BAYES, foo, "Expense#Food"}, val2);
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + pepper + "/" + "Asset-Bank").c_str(), val1);
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + "Asset-Bank#Bank").c_str(), new KvpValue{*val1});
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + "Asset>Bank#Bank").c_str(), val2);
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + pork + "/" + "Expense#Food").c_str(), new KvpValue{*val2});
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + sausage + "/" + "Expense#Drink").c_str(), val3);
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + "Expense#Food").c_str(), new KvpValue{*val2});
 
     EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account)));
     EXPECT_TRUE(qof_instance_get_dirty_flag(QOF_INSTANCE(t_bank_account)));
@@ -361,24 +364,24 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
     gnc_account_imap_convert_bayes (t_imap->book);
 
     // convert from 'Asset-Bank' to 'Asset-Bank' guid
-    value = root->get_slot({IMAP_FRAME_BAYES, pepper, acct3_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct3_guid).c_str());
     EXPECT_EQ(10, value->get<int64_t>());
 
     // convert from 'Asset-Bank#Bank' to 'Sav Bank' guid
-    value = root->get_slot({IMAP_FRAME_BAYES, salt, acct4_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct4_guid).c_str());
     EXPECT_EQ(10, value->get<int64_t>());
 
     // convert from 'Expense#Food' to 'Food' guid
-    value = root->get_slot({IMAP_FRAME_BAYES, pork, acct1_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + pork + "-" + acct1_guid).c_str());
     EXPECT_EQ(5, value->get<int64_t>());
 
     // convert from 'Expense#Drink' to 'Drink' guid
-    value = root->get_slot({IMAP_FRAME_BAYES, sausage, acct2_guid});
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + sausage + "-" + acct2_guid).c_str());
     EXPECT_EQ(2, value->get<int64_t>());
 
     // convert from 'Expense#Food' to 'Food' guid but add to original value
-    value = root->get_slot({IMAP_FRAME_BAYES, foo, acct1_guid});
-    EXPECT_EQ(6, value->get<int64_t>());
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct1_guid).c_str());
+    EXPECT_EQ(5, value->get<int64_t>());
 
     // Check for run once flag
     auto vals = book->get_slot("changed-bayesian-to-guid");
@@ -388,4 +391,53 @@ TEST_F(ImapBayesTest, ConvertAccountBayes)
     EXPECT_TRUE(qof_instance_get_dirty_flag(QOF_INSTANCE(t_bank_account)));
 }
 
+TEST_F (ImapBayesTest, convert_map_flat)
+{
+    // prevent the embedded beginedit/committedit from doing anything
+    qof_instance_increase_editlevel(QOF_INSTANCE(t_bank_account));
+    qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
+    //gnc_account_imap_add_account_bayes(t_imap, t_list1, t_expense_account1); //Food
+    //gnc_account_imap_add_account_bayes(t_imap, t_list2, t_expense_account2); //Drink
+    auto root = qof_instance_get_slots(QOF_INSTANCE(t_bank_account));
+    auto acct1_guid = guid_to_string (xaccAccountGetGUID(t_expense_account1)); //Food
+    auto acct2_guid = guid_to_string (xaccAccountGetGUID(t_expense_account2)); //Drink
+    auto acct3_guid = guid_to_string (xaccAccountGetGUID(t_asset_account2)); //Asset-Bank
+    auto acct4_guid = guid_to_string (xaccAccountGetGUID(t_sav_account)); //Sav Bank
+    auto val1 = new KvpValue(static_cast<int64_t>(10));
+    auto val2 = new KvpValue(static_cast<int64_t>(5));
+    auto val3 = new KvpValue(static_cast<int64_t>(2));
+    // Set up some old entries
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + pepper + "/" + acct1_guid).c_str(), val1);
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + acct2_guid).c_str(), new KvpValue{*val1});
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + acct3_guid).c_str(), val2);
+    root->set_path((std::string{IMAP_FRAME_BAYES} + "/" + pork + "/" + acct4_guid).c_str(), val3);
+    EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account)));
+    qof_instance_mark_clean(QOF_INSTANCE(t_bank_account));
+    gnc_account_imap_convert_flat (t_imap->book);
+    auto value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + pepper + "-" + acct1_guid).c_str());
+    EXPECT_EQ(10, value->get<int64_t>());
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + salt + "-" + acct2_guid).c_str());
+    EXPECT_EQ(10, value->get<int64_t>());
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + foo + "-" + acct3_guid).c_str());
+    EXPECT_EQ(5, value->get<int64_t>());
+    value = root->get_slot((std::string{IMAP_FRAME_BAYES} + "-" + pork + "-" + acct4_guid).c_str());
+    EXPECT_EQ(2, value->get<int64_t>());
+    auto book = qof_instance_get_slots(QOF_INSTANCE(t_imap->book));
+    auto vals = book->get_slot("changed-bayesian-to-flat");
+    EXPECT_STREQ("true", vals->get<const char*>());
+    EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account)));
+    EXPECT_TRUE(qof_instance_get_dirty_flag(QOF_INSTANCE(t_bank_account)));
+}
 
+/* Tests the import map's handling of KVP delimiters */
+TEST_F (ImapBayesTest, import_map_with_delimiters)
+{
+    GList * tokens {nullptr};
+    tokens = g_list_prepend(tokens, const_cast<char*>("one/two/three"));
+    gnc_account_imap_add_account_bayes(t_imap, tokens, t_expense_account1);
+    gnc_account_imap_add_account_bayes(t_imap, tokens, t_expense_account1);
+    gnc_account_imap_add_account_bayes(t_imap, tokens, t_expense_account1);
+
+    auto account = gnc_account_imap_find_account_bayes (t_imap, tokens);
+    EXPECT_EQ (account, t_expense_account1);
+}
diff --git a/libgnucash/engine/test/test-kvp-frame.cpp b/libgnucash/engine/test/test-kvp-frame.cpp
index 3df1c75..d67639f 100644
--- a/libgnucash/engine/test/test-kvp-frame.cpp
+++ b/libgnucash/engine/test/test-kvp-frame.cpp
@@ -202,3 +202,41 @@ TEST_F (KvpFrameTest, Empty)
     EXPECT_TRUE(f1.empty());
     EXPECT_FALSE(f2.empty());
 }
+
+TEST (KvpFrameTestForEachPrefix, for_each_prefix_1)
+{
+    KvpFrame fr;
+    fr.set("one", new KvpValue{new KvpFrame});
+    fr.set("one/two", new KvpValue{new KvpFrame});
+    fr.set("top/two/three", new KvpValue {15.0});
+    fr.set("onetwo", new KvpValue{new KvpFrame});
+    fr.set("onetwo/three", new KvpValue {15.0});
+    fr.set("onetwothree", new KvpValue {(int64_t)52});
+    unsigned count {};
+    auto counter = [] (char const *, KvpValue*, unsigned & count) { ++count; };
+    fr.for_each_slot_prefix("one", counter, count);
+    EXPECT_EQ(count, 3);
+    count = 0;
+    fr.for_each_slot_prefix("onetwo", counter, count);
+    EXPECT_EQ(count, 2);
+    count = 0;
+    fr.for_each_slot_prefix("onetwothree", counter, count);
+    EXPECT_EQ(count, 1);
+    count = 0;
+    fr.for_each_slot_prefix("two", counter, count);
+    EXPECT_EQ(count, 0);
+}
+
+TEST (KvpFrameTestForEachPrefix, for_each_prefix_2)
+{
+    KvpFrame fr;
+    fr.set("onetwo/three", new KvpValue {15.0});
+    fr.set("onethree", new KvpValue {(int64_t)52});
+    unsigned count;
+    fr.for_each_slot_prefix("onetwo", [](char const *, KvpValue * value, unsigned) {
+            EXPECT_EQ(value->get_type(), KvpValue::Type::FRAME);
+        }, count);
+    fr.for_each_slot_prefix("onetwo", [](char const *, KvpValue * value, unsigned) {
+            EXPECT_EQ(value->get_type(), KvpValue::Type::INT64);
+        }, count);
+}
diff --git a/libgnucash/engine/test/utest-Split.cpp b/libgnucash/engine/test/utest-Split.cpp
index 09234a6..d60fbe1 100644
--- a/libgnucash/engine/test/utest-Split.cpp
+++ b/libgnucash/engine/test/utest-Split.cpp
@@ -740,7 +740,7 @@ test_xaccSplitDetermineGainStatus (Fixture *fixture, gconstpointer pData)
     g_assert (fixture->split->gains_split == NULL);
     g_assert_cmpint (fixture->split->gains, ==, GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY);
 
-    fixture->split->inst.kvp_data->set("gains-source", new KvpValue(const_cast<GncGUID*>(guid_copy(g_guid))));
+    fixture->split->inst.kvp_data->set("gains-source", new KvpValue(guid_copy(g_guid)));
     g_assert (fixture->split->gains_split == NULL);
     fixture->split->gains = GAINS_STATUS_UNKNOWN;
     xaccSplitDetermineGainStatus (fixture->split);

commit 08aa0104ef3f439b0bc9a9708d97440b4bf8b221
Author: lmat <dartme18 at gmail.com>
Date:   Thu Oct 19 15:23:16 2017 -0400

    Change kvp string representation
    
    The nested representation was very noisy. Now, the string representation
    shows one line per value with the full prefix which is also more
    expressive than the old version.

diff --git a/libgnucash/engine/kvp-frame.cpp b/libgnucash/engine/kvp-frame.cpp
index 0610135..13a0e4e 100644
--- a/libgnucash/engine/kvp-frame.cpp
+++ b/libgnucash/engine/kvp-frame.cpp
@@ -181,23 +181,30 @@ KvpFrameImpl::set_path(Path path, KvpValue* value) noexcept
 std::string
 KvpFrameImpl::to_string() const noexcept
 {
-    std::ostringstream ret;
-    ret << "{\n";
+    return to_string("");
+}
 
+std::string
+KvpFrameImpl::to_string(std::string const & prefix) const noexcept
+{
+    if (!m_valuemap.size())
+        return prefix;
+    std::ostringstream ret;
     std::for_each(m_valuemap.begin(), m_valuemap.end(),
-        [this,&ret](const map_type::value_type &a)
+        [this,&ret,&prefix](const map_type::value_type &a)
         {
-            ret << "    ";
+            std::string new_prefix {prefix};
             if (a.first)
-                ret << a.first;
-            ret << " => ";
+            {
+                new_prefix += a.first;
+                new_prefix += "/";
+            }
             if (a.second)
-                ret << a.second->to_string();
-            ret << ",\n";
+                ret << a.second->to_string(new_prefix) << "\n";
+            else
+                ret << new_prefix << "(null)\n";
         }
     );
-
-    ret << "}\n";
     return ret.str();
 }
 
diff --git a/libgnucash/engine/kvp-frame.hpp b/libgnucash/engine/kvp-frame.hpp
index e5308ec..1af4217 100644
--- a/libgnucash/engine/kvp-frame.hpp
+++ b/libgnucash/engine/kvp-frame.hpp
@@ -188,6 +188,12 @@ struct KvpFrameImpl
      */
     std::string to_string() const noexcept;
     /**
+     * Make a string representation of the frame with the specified string
+     * prefixed to every item in the frame.
+     * @return A std::string representing all the children of the frame.
+     */
+    std::string to_string(std::string const & prefix) const noexcept;
+    /**
      * Report the keys in the immediate frame. Be sensible about using this, it
      * isn't a very efficient way to iterate.
      * @return std::vector of keys as std::strings.
diff --git a/libgnucash/engine/kvp-value.cpp b/libgnucash/engine/kvp-value.cpp
index 55e0e6e..a0329d2 100644
--- a/libgnucash/engine/kvp-value.cpp
+++ b/libgnucash/engine/kvp-value.cpp
@@ -125,34 +125,32 @@ struct to_string_visitor : boost::static_visitor<void>
 
     void operator()(int64_t val)
     {
-        output << "KVP_VALUE_GINT64(" << val << ")";
+        output << val << " (64-bit int)";
     }
 
-    void operator()(KvpFrame * val)
+    void operator()(KvpFrame* val)
     {
-        output << "KVP_VALUE_FRAME(" << val->to_string() << ")";
+        output << val->to_string();
     }
 
     void operator()(GDate val)
     {
-        output << "KVP_VALUE_GDATE(";
         output << std::setw(4) << g_date_get_year(&val) << '-';
         output << std::setw(2) << g_date_get_month(&val) << '-';
-        output << std::setw(2) << g_date_get_day(&val) << ')';
+        output << std::setw(2) << g_date_get_day(&val);
+        output << " (gdate)";
     }
 
     void operator()(GList * val)
     {
         output << "KVP_VALUE_GLIST(";
         output << "[ ";
-
         /*Since val is passed by value, we can modify it*/
         for (;val; val = val->next)
         {
             auto realvalue = static_cast<const KvpValue *>(val->data);
             output << ' ' << realvalue->to_string() << ',';
         }
-
         output << " ]";
         output << ")";
     }
@@ -161,53 +159,66 @@ struct to_string_visitor : boost::static_visitor<void>
     {
         char tmp1[40] {};
         gnc_timespec_to_iso8601_buff (val, tmp1);
-        output << "KVP_VALUE_TIMESPEC(" << tmp1 << ")";
+        output << tmp1 << " (timespec)";
     }
 
     void operator()(gnc_numeric val)
     {
         auto tmp1 = gnc_numeric_to_string(val);
-        output << "KVP_VALUE_NUMERIC(";
         if (tmp1)
         {
             output << tmp1;
             g_free(tmp1);
         }
-        output << ")";
+        else
+        {
+            output << "(null)";
+        }
+        output << " (timespec)";
     }
 
     void operator()(GncGUID * val)
     {
         char guidstr[GUID_ENCODING_LENGTH+1];
-        output << "KVP_VALUE_GUID(";
         if (val)
         {
             guid_to_string_buff(val,guidstr);
             output << guidstr;
         }
-        output << ")";
+        else
+        {
+            output << "(null)";
+        }
+        output << " (guid)";
     }
 
     void operator()(const char * val)
     {
-        output << "KVP_VALUE_STRING(" << val << ")";
+        output << val << " (char *)";
     }
 
     void operator()(double val)
     {
-        output << "KVP_VALUE_DOUBLE(" << val << ")";
+        output << val << " (double)";
     }
 };
 
 std::string
-KvpValueImpl::to_string() const noexcept
+KvpValueImpl::to_string(std::string const & prefix) const noexcept
 {
+    if (this->datastore.type() == typeid(KvpFrame*))
+        return this->get<KvpFrame*>()->to_string(prefix);
     std::ostringstream ret;
     to_string_visitor visitor {ret};
     boost::apply_visitor(visitor, datastore);
-
     /*We still use g_strdup since the return value will be freed by g_free*/
-    return ret.str();
+    return prefix + ret.str();
+}
+
+std::string
+KvpValueImpl::to_string() const noexcept
+{
+    return to_string("");
 }
 
 static int
diff --git a/libgnucash/engine/kvp-value.hpp b/libgnucash/engine/kvp-value.hpp
index 003ee7d..78a8eb7 100644
--- a/libgnucash/engine/kvp-value.hpp
+++ b/libgnucash/engine/kvp-value.hpp
@@ -138,6 +138,7 @@ struct KvpValueImpl
     KvpValueImpl::Type get_type() const noexcept;
 
     std::string to_string() const noexcept;
+    std::string to_string(std::string const & prefix) const noexcept;
 
     template <typename T>
     T get() const noexcept;
diff --git a/libgnucash/engine/test/utest-Transaction.cpp b/libgnucash/engine/test/utest-Transaction.cpp
index dde0a48..a95a5ac 100644
--- a/libgnucash/engine/test/utest-Transaction.cpp
+++ b/libgnucash/engine/test/utest-Transaction.cpp
@@ -885,7 +885,7 @@ test_xaccTransEqual (Fixture *fixture, gconstpointer pData)
     xaccTransCommitEdit (clone);
     g_free (cleanup->msg);
     g_free (check->msg);
-    check->msg = g_strdup ("[xaccTransEqual] kvp frames differ:\n{\n    notes => KVP_VALUE_STRING(Salt pork sausage),\n    qux => KVP_VALUE_FRAME({\n    quux => KVP_VALUE_FRAME({\n    corge => KVP_VALUE_DOUBLE(654.321),\n}\n),\n}\n),\n}\n\n\nvs\n\n{\n    notes => KVP_VALUE_STRING(Salt pork sausage),\n    qux => KVP_VALUE_FRAME({\n    quux => KVP_VALUE_FRAME({\n    corge => KVP_VALUE_DOUBLE(123.456),\n}\n),\n}\n),\n}\n");
+    check->msg = g_strdup ("[xaccTransEqual] kvp frames differ:\nnotes/Salt pork sausage (char *)\nqux/quux/corge/654.321 (double)\n\n\n\n\nvs\n\nnotes/Salt pork sausage (char *)\nqux/quux/corge/123.456 (double)\n\n\n");
 
     g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
 

commit 34e0d6cfa06648e38d0771363803f2468efdc01c
Author: lmat <dartme18 at gmail.com>
Date:   Thu Oct 5 12:48:37 2017 -0400

    kvp frame to template and correcting failure macro
    
    The template avoids the need to cast to and from void*, and adds flexibility to
    the targeted function's signature.
    
    test-stuff.h defines a macro, "failure" which is used as an identifier
    in the standard IO library, so I moved any inclusion of test-stuff.h to
    the last include position so that "failure" wouldn't be defined before
    the IO library was included.

diff --git a/common/test-core/test-stuff.h b/common/test-core/test-stuff.h
index 8fcd506..6da2adb 100644
--- a/common/test-core/test-stuff.h
+++ b/common/test-core/test-stuff.h
@@ -57,7 +57,9 @@ Otherwise, only failures are printed out.
 #include <glib.h>
 #include <stdlib.h>
 
-
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 /* Privately used to indicate a test result. You may use these if you
  * wish, but it's easier to use the do_test macro above.
@@ -150,5 +152,8 @@ gint64 get_random_gint64(void);
 double get_random_double(void);
 const char* get_random_string_in_array(const char* str_list[]);
 
+#ifdef __cplusplus
+} /*extern "C"*/
+#endif
 
 #endif /* TEST_STUFF_H */
diff --git a/libgnucash/backend/sql/gnc-slots-sql.cpp b/libgnucash/backend/sql/gnc-slots-sql.cpp
index 8b35b27..30563a5 100644
--- a/libgnucash/backend/sql/gnc-slots-sql.cpp
+++ b/libgnucash/backend/sql/gnc-slots-sql.cpp
@@ -581,81 +581,78 @@ slot_info_copy (slot_info_t* pInfo, GncGUID* guid)
 }
 
 static void
-save_slot (const char* key, KvpValue* value, gpointer data)
+save_slot (const char* key, KvpValue* value, slot_info_t & slot_info)
 {
-    slot_info_t* pSlot_info = (slot_info_t*)data;
-
     g_return_if_fail (value != NULL);
-    g_return_if_fail (data != NULL);
 
     // Ignore if we've already run into a failure
-    if (!pSlot_info->is_ok)
+    if (!slot_info.is_ok)
     {
         return;
     }
-    auto curlen = pSlot_info->path.length();
-    pSlot_info->pKvpValue = value;
+    auto curlen = slot_info.path.length();
+    slot_info.pKvpValue = value;
     if (curlen != 0)
-        pSlot_info->path += "/";
+        slot_info.path += "/";
 
-    pSlot_info->path += key;
-    pSlot_info->value_type = value->get_type ();
+    slot_info.path += key;
+    slot_info.value_type = value->get_type ();
 
-    switch (pSlot_info->value_type)
+    switch (slot_info.value_type)
     {
     case KvpValue::Type::FRAME:
     {
         auto pKvpFrame = value->get<KvpFrame*> ();
         auto guid = guid_new ();
-        slot_info_t* pNewInfo = slot_info_copy (pSlot_info, guid);
-        KvpValue* oldValue = pSlot_info->pKvpValue;
-        pSlot_info->pKvpValue = new KvpValue {guid};
-        pSlot_info->is_ok = pSlot_info->be->do_db_operation(OP_DB_INSERT,
+        slot_info_t* pNewInfo = slot_info_copy (&slot_info, guid);
+        KvpValue* oldValue = slot_info.pKvpValue;
+        slot_info.pKvpValue = new KvpValue {guid};
+        slot_info.is_ok = slot_info.be->do_db_operation(OP_DB_INSERT,
                                                             TABLE_NAME,
                                                             TABLE_NAME,
-                                                            pSlot_info,
+                                                            &slot_info,
                                                             col_table);
-        g_return_if_fail (pSlot_info->is_ok);
-        pKvpFrame->for_each_slot (save_slot, pNewInfo);
-        delete pSlot_info->pKvpValue;
-        pSlot_info->pKvpValue = oldValue;
+        g_return_if_fail (slot_info.is_ok);
+        pKvpFrame->for_each_slot_temp (save_slot, *pNewInfo);
+        delete slot_info.pKvpValue;
+        slot_info.pKvpValue = oldValue;
         delete pNewInfo;
     }
     break;
     case KvpValue::Type::GLIST:
     {
         GncGUID* guid = guid_new ();
-        slot_info_t* pNewInfo = slot_info_copy (pSlot_info, guid);
-        KvpValue* oldValue = pSlot_info->pKvpValue;
-        pSlot_info->pKvpValue = new KvpValue {guid};  // Transfer ownership!
-        pSlot_info->is_ok = pSlot_info->be->do_db_operation(OP_DB_INSERT,
+        slot_info_t* pNewInfo = slot_info_copy (&slot_info, guid);
+        KvpValue* oldValue = slot_info.pKvpValue;
+        slot_info.pKvpValue = new KvpValue {guid};  // Transfer ownership!
+        slot_info.is_ok = slot_info.be->do_db_operation(OP_DB_INSERT,
                                                             TABLE_NAME,
                                                             TABLE_NAME,
-                                                            pSlot_info,
+                                                            &slot_info,
                                                             col_table);
-        g_return_if_fail (pSlot_info->is_ok);
+        g_return_if_fail (slot_info.is_ok);
         for (auto cursor = value->get<GList*> (); cursor; cursor = cursor->next)
         {
             auto val = static_cast<KvpValue*> (cursor->data);
-            save_slot ("", val, pNewInfo);
+            save_slot ("", val, *pNewInfo);
         }
-        delete pSlot_info->pKvpValue;
-        pSlot_info->pKvpValue = oldValue;
+        delete slot_info.pKvpValue;
+        slot_info.pKvpValue = oldValue;
         delete pNewInfo;
     }
     break;
     default:
     {
-        pSlot_info->is_ok = pSlot_info->be->do_db_operation (OP_DB_INSERT,
+        slot_info.is_ok = slot_info.be->do_db_operation (OP_DB_INSERT,
                                                              TABLE_NAME,
                                                              TABLE_NAME,
-                                                             pSlot_info,
+                                                             &slot_info,
                                                              col_table);
     }
     break;
     }
 
-    pSlot_info->path.erase(curlen);
+    slot_info.path.erase(curlen);
 }
 
 gboolean
@@ -678,7 +675,7 @@ gnc_sql_slots_save (GncSqlBackend* sql_be, const GncGUID* guid, gboolean is_infa
 
     slot_info.be = sql_be;
     slot_info.guid = guid;
-    pFrame->for_each_slot (save_slot, &slot_info);
+    pFrame->for_each_slot_temp (save_slot, slot_info);
 
     return slot_info.is_ok;
 }
diff --git a/libgnucash/backend/xml/sixtp-dom-generators.cpp b/libgnucash/backend/xml/sixtp-dom-generators.cpp
index 22a3f7e..25504dd 100644
--- a/libgnucash/backend/xml/sixtp-dom-generators.cpp
+++ b/libgnucash/backend/xml/sixtp-dom-generators.cpp
@@ -334,7 +334,7 @@ add_kvp_value_node (xmlNodePtr node, const gchar* tag, KvpValue* val)
         auto frame = val->get<KvpFrame*> ();
         if (!frame)
             break;
-        frame->for_each_slot (add_kvp_slot, static_cast<void*> (val_node));
+        frame->for_each_slot_temp (&add_kvp_slot, val_node);
         break;
     }
     default:
@@ -366,6 +366,6 @@ qof_instance_slots_to_dom_tree (const char* tag, const QofInstance* inst)
         return nullptr;
 
     ret = xmlNewNode (nullptr, BAD_CAST tag);
-    frame->for_each_slot (add_kvp_slot, static_cast<void*> (ret));
+    frame->for_each_slot_temp (&add_kvp_slot, ret);
     return ret;
 }
diff --git a/libgnucash/backend/xml/test/test-date-converting.cpp b/libgnucash/backend/xml/test/test-date-converting.cpp
index 992ee85..cae7c19 100644
--- a/libgnucash/backend/xml/test/test-date-converting.cpp
+++ b/libgnucash/backend/xml/test/test-date-converting.cpp
@@ -21,7 +21,6 @@ extern "C"
 {
 #include <config.h>
 
-#include "test-stuff.h"
 #include "test-engine-stuff.h"
 
 #include <stdlib.h>
@@ -30,6 +29,7 @@ extern "C"
 #include "test-file-stuff.h"
 #include "sixtp-utils.h"
 #include "sixtp-dom-generators.h"
+#include "test-stuff.h"
 
 #define GNC_V2_STRING "gnc-v2"
 const gchar* gnc_v2_xml_version_string = GNC_V2_STRING;
diff --git a/libgnucash/backend/xml/test/test-dom-converters1.cpp b/libgnucash/backend/xml/test/test-dom-converters1.cpp
index d5499d9..1035c6e 100644
--- a/libgnucash/backend/xml/test/test-dom-converters1.cpp
+++ b/libgnucash/backend/xml/test/test-dom-converters1.cpp
@@ -30,7 +30,6 @@ extern "C"
 
 #include <glib.h>
 
-#include "test-stuff.h"
 #include "test-engine-stuff.h"
 #include "cashobjects.h"
 #include "gnc-engine.h"
@@ -44,6 +43,7 @@ extern "C"
 #include "sixtp-utils.h"
 #include "sixtp-dom-parsers.h"
 #include "sixtp-dom-generators.h"
+#include "test-stuff.h"
 
 #define GNC_V2_STRING "gnc-v2"
 const gchar* gnc_v2_xml_version_string = GNC_V2_STRING;
diff --git a/libgnucash/backend/xml/test/test-load-example-account.cpp b/libgnucash/backend/xml/test/test-load-example-account.cpp
index 576ddd1..8193ba3 100644
--- a/libgnucash/backend/xml/test/test-load-example-account.cpp
+++ b/libgnucash/backend/xml/test/test-load-example-account.cpp
@@ -34,7 +34,6 @@ extern "C"
 
 #include "gnc-module.h"
 #include "gnc-engine.h"
-#include "test-stuff.h"
 #include "test-engine-stuff.h"
 }
 
@@ -43,6 +42,7 @@ extern "C"
 #include "io-gncxml-v2.h"
 
 #include "io-example-account.h"
+#include "test-stuff.h"
 
 static const gchar* da_ending = ".gnucash-xea";
 
diff --git a/libgnucash/backend/xml/test/test-load-xml2.cpp b/libgnucash/backend/xml/test/test-load-xml2.cpp
index 7731f88..f417fd6 100644
--- a/libgnucash/backend/xml/test/test-load-xml2.cpp
+++ b/libgnucash/backend/xml/test/test-load-xml2.cpp
@@ -45,7 +45,6 @@ extern "C"
 #include <gnc-engine.h>
 #include <gnc-prefs.h>
 
-#include <test-stuff.h>
 #include <unittest-support.h>
 #include <test-engine-stuff.h>
 }
@@ -53,6 +52,7 @@ extern "C"
 #include "../gnc-backend-xml.h"
 #include "../io-gncxml-v2.h"
 #include "test-file-stuff.h"
+#include <test-stuff.h>
 
 #define GNC_LIB_NAME "gncmod-backend-xml"
 #define GNC_LIB_REL_PATH "xml"
diff --git a/libgnucash/backend/xml/test/test-save-in-lang.cpp b/libgnucash/backend/xml/test/test-save-in-lang.cpp
index f7c0fb7..6705348 100644
--- a/libgnucash/backend/xml/test/test-save-in-lang.cpp
+++ b/libgnucash/backend/xml/test/test-save-in-lang.cpp
@@ -30,7 +30,6 @@ extern "C"
 #include <stdlib.h>
 #include <string.h>
 
-#include "test-stuff.h"
 #include "test-engine-stuff.h"
 
 #include "gnc-engine.h"
@@ -39,6 +38,7 @@ extern "C"
 
 #include "test-file-stuff.h"
 #include "io-gncxml-v2.h"
+#include "test-stuff.h"
 
 const char* possible_envs[] =
 {
diff --git a/libgnucash/backend/xml/test/test-string-converters.cpp b/libgnucash/backend/xml/test/test-string-converters.cpp
index a8ad66a..72f74ba 100644
--- a/libgnucash/backend/xml/test/test-string-converters.cpp
+++ b/libgnucash/backend/xml/test/test-string-converters.cpp
@@ -24,13 +24,13 @@ extern "C"
 #include <stdlib.h>
 #include "gnc-engine.h"
 
-#include "test-stuff.h"
 #include "test-engine-stuff.h"
 }
 
 #include "test-file-stuff.h"
 #include "sixtp-dom-parsers.h"
 #include "sixtp-dom-generators.h"
+#include "test-stuff.h"
 
 
 #define GNC_V2_STRING "gnc-v2"
diff --git a/libgnucash/backend/xml/test/test-xml-account.cpp b/libgnucash/backend/xml/test/test-xml-account.cpp
index 8a1eb87..5022a91 100644
--- a/libgnucash/backend/xml/test/test-xml-account.cpp
+++ b/libgnucash/backend/xml/test/test-xml-account.cpp
@@ -32,7 +32,6 @@ extern "C"
 #include <gnc-engine.h>
 #include <cashobjects.h>
 
-#include <test-stuff.h>
 #include <test-engine-stuff.h>
 #include <unittest-support.h>
 
@@ -45,6 +44,7 @@ extern "C"
 #include "../sixtp-parsers.h"
 #include "../sixtp-dom-parsers.h"
 #include "test-file-stuff.h"
+#include <test-stuff.h>
 
 static QofBook* sixbook;
 
diff --git a/libgnucash/backend/xml/test/test-xml-commodity.cpp b/libgnucash/backend/xml/test/test-xml-commodity.cpp
index 07f8f43..71a3060 100644
--- a/libgnucash/backend/xml/test/test-xml-commodity.cpp
+++ b/libgnucash/backend/xml/test/test-xml-commodity.cpp
@@ -28,7 +28,6 @@ extern "C"
 
 #include "gnc-module.h"
 #include "qof.h"
-#include "test-stuff.h"
 #include "test-engine-stuff.h"
 
 #include "Account.h"
@@ -41,6 +40,7 @@ extern "C"
 #include "sixtp-dom-parsers.h"
 #include "io-gncxml-gen.h"
 #include "test-file-stuff.h"
+#include "test-stuff.h"
 
 static QofBook* book;
 
diff --git a/libgnucash/backend/xml/test/test-xml-pricedb.cpp b/libgnucash/backend/xml/test/test-xml-pricedb.cpp
index 4ab584d..18d22ef 100644
--- a/libgnucash/backend/xml/test/test-xml-pricedb.cpp
+++ b/libgnucash/backend/xml/test/test-xml-pricedb.cpp
@@ -34,7 +34,6 @@ extern "C"
 #include "gnc-engine.h"
 #include "gnc-pricedb.h"
 
-#include "test-stuff.h"
 #include "test-engine-stuff.h"
 }
 
@@ -45,6 +44,7 @@ extern "C"
 #include "sixtp-dom-parsers.h"
 #include "io-gncxml-v2.h"
 #include "test-file-stuff.h"
+#include "test-stuff.h"
 
 static QofSession* session;
 static int iter;
diff --git a/libgnucash/backend/xml/test/test-xml-transaction.cpp b/libgnucash/backend/xml/test/test-xml-transaction.cpp
index 5828b43..1154b3b 100644
--- a/libgnucash/backend/xml/test/test-xml-transaction.cpp
+++ b/libgnucash/backend/xml/test/test-xml-transaction.cpp
@@ -38,7 +38,6 @@ extern "C"
 #include <cashobjects.h>
 #include <TransLog.h>
 
-#include <test-stuff.h>
 #include <test-engine-stuff.h>
 #include <unittest-support.h>
 
@@ -53,7 +52,7 @@ extern "C"
 #include "../sixtp-dom-parsers.h"
 #include "../io-gncxml-gen.h"
 #include "test-file-stuff.h"
-
+#include <test-stuff.h>
 static QofBook* book;
 
 extern gboolean gnc_transaction_xml_v2_testing;
diff --git a/libgnucash/backend/xml/test/test-xml2-is-file.cpp b/libgnucash/backend/xml/test/test-xml2-is-file.cpp
index f4234e6..8b698f4 100644
--- a/libgnucash/backend/xml/test/test-xml2-is-file.cpp
+++ b/libgnucash/backend/xml/test/test-xml2-is-file.cpp
@@ -23,12 +23,12 @@ extern "C"
 #include <stdlib.h>
 #include <string.h>
 
-#include "test-stuff.h"
 #include "test-engine-stuff.h"
 }
 
 #include "io-gncxml-v2.h"
 #include "test-file-stuff.h"
+#include "test-stuff.h"
 
 #define FILENAME "Money95bank_fr.gml2"
 
diff --git a/libgnucash/engine/gnc-aqbanking-templates.cpp b/libgnucash/engine/gnc-aqbanking-templates.cpp
index eb8d6e7..fe2c37d 100644
--- a/libgnucash/engine/gnc-aqbanking-templates.cpp
+++ b/libgnucash/engine/gnc-aqbanking-templates.cpp
@@ -30,9 +30,9 @@
 extern "C"
 {
 #include "gnc-aqbanking-templates.h"
-#include "qofinstance-p.h"
 }
 
+#include "qofinstance-p.h"
 #include "kvp-frame.hpp"
 #include "gnc-rational.hpp"
 
diff --git a/libgnucash/engine/kvp-frame.cpp b/libgnucash/engine/kvp-frame.cpp
index f1368bc..0610135 100644
--- a/libgnucash/engine/kvp-frame.cpp
+++ b/libgnucash/engine/kvp-frame.cpp
@@ -214,20 +214,6 @@ KvpFrameImpl::get_keys() const noexcept
     return ret;
 }
 
-void
-KvpFrameImpl::for_each_slot(void (*proc)(const char *key, KvpValue *value,
-                                         void * data),
-                            void *data) const noexcept
-{
-    if (!proc) return;
-    std::for_each (m_valuemap.begin(), m_valuemap.end(),
-        [proc,data](const KvpFrameImpl::map_type::value_type & a)
-        {
-            proc (a.first, a.second, data);
-        }
-    );
-}
-
 KvpValueImpl *
 KvpFrameImpl::get_slot(const char * key) const noexcept
 {
diff --git a/libgnucash/engine/kvp-frame.hpp b/libgnucash/engine/kvp-frame.hpp
index 52908cd..e5308ec 100644
--- a/libgnucash/engine/kvp-frame.hpp
+++ b/libgnucash/engine/kvp-frame.hpp
@@ -204,11 +204,15 @@ struct KvpFrameImpl
      * @return The value at the key or nullptr.
      */
     KvpValue* get_slot(Path keys) const noexcept;
-    /** Convenience wrapper for std::for_each, which should be preferred.
+
+    void for_each_slot(void (*)(char const *key, KvpValue*, void*data), void*data) const noexcept;
+
+    /** The function should be of the form:
+     * <anything> func (char const *, KvpValue *, data_type &);
+     * Do not pass nullptr for the function.
      */
-    void for_each_slot(void (*proc)(const char *key, KvpValue *value,
-                                    void * data),
-                       void *data) const noexcept;
+    template <typename func_type, typename data_type>
+    void for_each_slot_temp (func_type const &, data_type &) const noexcept;
 
     /** Test for emptiness
      * @return true if the frame contains nothing.
@@ -220,6 +224,18 @@ struct KvpFrameImpl
     map_type m_valuemap;
 };
 
+template <typename func_type, typename data_type>
+void KvpFrame::for_each_slot_temp(func_type const & func, data_type & data) const noexcept
+{
+    std::for_each (m_valuemap.begin(), m_valuemap.end(),
+        [&func,&data](const KvpFrameImpl::map_type::value_type & a)
+        {
+            func (a.first, a.second, data);
+        }
+    );
+}
+
+
 int compare (const KvpFrameImpl &, const KvpFrameImpl &) noexcept;
 int compare (const KvpFrameImpl *, const KvpFrameImpl *) noexcept;
 /** @} Doxygen Group */
diff --git a/libgnucash/engine/qof-backend.hpp b/libgnucash/engine/qof-backend.hpp
index 871fec8..ce0df97 100644
--- a/libgnucash/engine/qof-backend.hpp
+++ b/libgnucash/engine/qof-backend.hpp
@@ -45,12 +45,12 @@ extern "C"
 {
 #include "qofbackend.h"
 #include "qofbook.h"
-#include "qofinstance-p.h"
 #include "qofquery.h"
 #include "qofsession.h"
 #include <gmodule.h>
 }
 
+#include "qofinstance-p.h"
 #include <string>
 #include <algorithm>
 #include <vector>
diff --git a/libgnucash/engine/qofbook.cpp b/libgnucash/engine/qofbook.cpp
index 2bcbebc..4a57af9 100644
--- a/libgnucash/engine/qofbook.cpp
+++ b/libgnucash/engine/qofbook.cpp
@@ -1118,7 +1118,7 @@ static void commit_err (G_GNUC_UNUSED QofInstance *inst, QofBackendError errcode
 
 #define GNC_FEATURES "features"
 static void
-add_feature_to_hash (const gchar *key, KvpValue *value, gpointer user_data)
+add_feature_to_hash (const gchar *key, KvpValue *value, GHashTable * user_data)
 {
     gchar *descr = g_strdup(value->get<const char*>());
     g_hash_table_insert (*(GHashTable**)user_data, (gchar*)key, descr);
@@ -1134,8 +1134,8 @@ qof_book_get_features (QofBook *book)
     auto slot = frame->get_slot(GNC_FEATURES);
     if (slot != nullptr)
     {
-	frame = slot->get<KvpFrame*>();
-	frame->for_each_slot(&add_feature_to_hash, &features);
+        frame = slot->get<KvpFrame*>();
+        frame->for_each_slot_temp(&add_feature_to_hash, features);
     }
     return features;
 }
diff --git a/libgnucash/engine/qofinstance-p.h b/libgnucash/engine/qofinstance-p.h
index 0c0d4fd..ca6a4c5 100644
--- a/libgnucash/engine/qofinstance-p.h
+++ b/libgnucash/engine/qofinstance-p.h
@@ -33,6 +33,8 @@
 #include "qofinstance.h"
 
 #ifdef __cplusplus
+#include "kvp-frame.hpp"
+#include <string>
 extern "C"
 {
 #endif
@@ -156,8 +158,19 @@ void qof_instance_foreach_slot (const QofInstance *inst, const char *path,
                                 void(*proc)(const char*, const GValue*, void*),
                                 void* data);
 #ifdef __cplusplus
+} /* extern "C" */
+
+/* Don't pass nullptr as the function */
+template<typename func_type, typename data_type>
+void qof_instance_foreach_slot_temp (QofInstance const * inst, std::string const & path,
+        func_type const & func, data_type & data)
+{
+    auto slot = inst->kvp_data->get_slot(path.c_str());
+    if (slot == nullptr || slot->get_type() != KvpValue::Type::FRAME)
+        return;
+    auto frame = slot->get<KvpFrame*>();
+    frame->for_each_slot(func, data);
 }
 #endif
 
-
 #endif /* QOF_INSTANCE_P_H */
diff --git a/libgnucash/engine/qofinstance.cpp b/libgnucash/engine/qofinstance.cpp
index c307aee..7994fb9 100644
--- a/libgnucash/engine/qofinstance.cpp
+++ b/libgnucash/engine/qofinstance.cpp
@@ -1278,10 +1278,9 @@ struct wrap_param
 };
 }
 static void
-wrap_gvalue_function (const char* key, KvpValue *val, gpointer data)
+wrap_gvalue_function (const char* key, KvpValue *val, wrap_param & param)
 {
     GValue *gv;
-    auto param = static_cast<wrap_param*>(data);
     if (val->get_type() != KvpValue::Type::FRAME)
         gv = gvalue_from_kvp_value(val);
     else
@@ -1290,7 +1289,7 @@ wrap_gvalue_function (const char* key, KvpValue *val, gpointer data)
         g_value_init (gv, G_TYPE_STRING);
         g_value_set_string (gv, nullptr);
     }
-    param->proc(key, gv, param->user_data);
+    param.proc(key, gv, param.user_data);
     g_slice_free (GValue, gv);
 }
 
@@ -1304,7 +1303,7 @@ qof_instance_foreach_slot (const QofInstance *inst, const char* path,
         return;
     auto frame = slot->get<KvpFrame*>();
     wrap_param new_data {proc, data};
-    frame->for_each_slot(wrap_gvalue_function, &new_data);
+    frame->for_each_slot_temp(&wrap_gvalue_function, new_data);
 }
 
 /* ========================== END OF FILE ======================= */
diff --git a/libgnucash/engine/qofsession.cpp b/libgnucash/engine/qofsession.cpp
index 45729ea..2049b5b 100644
--- a/libgnucash/engine/qofsession.cpp
+++ b/libgnucash/engine/qofsession.cpp
@@ -50,12 +50,12 @@ extern "C"
 
 #include <glib.h>
 #include "qof.h"
-#include "qofbook-p.h"
 #include "qofobject-p.h"
 
 static QofLogModule log_module = QOF_MOD_SESSION;
 } //extern 'C'
 
+#include "qofbook-p.h"
 #include "qof-backend.hpp"
 #include "qofsession.hpp"
 #include "gnc-backend-prov.hpp"
diff --git a/libgnucash/engine/test-core/test-engine-stuff.cpp b/libgnucash/engine/test-core/test-engine-stuff.cpp
index b95c14d..c4c4170 100644
--- a/libgnucash/engine/test-core/test-engine-stuff.cpp
+++ b/libgnucash/engine/test-core/test-engine-stuff.cpp
@@ -55,7 +55,6 @@ extern "C"
 #include <string.h>
 #include <sys/stat.h>
 #include <qof.h>
-#include <qofinstance-p.h>
 
 #include "Account.h"
 #include "AccountP.h"
@@ -71,6 +70,7 @@ extern "C"
 #include "test-stuff.h"
 #include "test-engine-strings.h"
 }
+#include <qofinstance-p.h>
 
 static gboolean glist_strings_only = FALSE;
 
diff --git a/libgnucash/engine/test/gtest-import-map.cpp b/libgnucash/engine/test/gtest-import-map.cpp
index 47746d6..f5f3cf2 100644
--- a/libgnucash/engine/test/gtest-import-map.cpp
+++ b/libgnucash/engine/test/gtest-import-map.cpp
@@ -25,9 +25,9 @@ extern "C"
 #include <config.h>
 #include "../Account.h"
 #include <qof.h>
-#include <qofinstance-p.h>
 }
 
+#include <qofinstance-p.h>
 #include <kvp-frame.hpp>
 #include <gtest/gtest.h>
 
diff --git a/libgnucash/engine/test/test-account-object.cpp b/libgnucash/engine/test/test-account-object.cpp
index 2872f85..32f612e 100644
--- a/libgnucash/engine/test/test-account-object.cpp
+++ b/libgnucash/engine/test/test-account-object.cpp
@@ -32,10 +32,10 @@ extern "C"
 #include "qof.h"
 #include "Account.h"
 #include "cashobjects.h"
-#include "test-stuff.h"
 #include "test-engine-stuff.h"
-#include <qofinstance-p.h>
 }
+#include <qofinstance-p.h>
+#include "test-stuff.h"
 
 static void
 run_test (void)
diff --git a/libgnucash/engine/test/utest-Account.cpp b/libgnucash/engine/test/utest-Account.cpp
index 3007907..4e59778 100644
--- a/libgnucash/engine/test/utest-Account.cpp
+++ b/libgnucash/engine/test/utest-Account.cpp
@@ -27,7 +27,6 @@ extern "C"
 #include <unittest-support.h>
 #include <gnc-event.h>
 #include <gnc-date.h>
-#include <qofinstance-p.h>
 /* Add specific headers for this class */
 #include "../Account.h"
 #include "../AccountP.h"
@@ -42,6 +41,7 @@ static const gchar *suitename = "/engine/Account";
 void test_suite_account (void);
 }
 
+#include <qofinstance-p.h>
 #include <kvp-frame.hpp>
 
 typedef struct
diff --git a/libgnucash/engine/test/utest-Split.cpp b/libgnucash/engine/test/utest-Split.cpp
index 7609242..09234a6 100644
--- a/libgnucash/engine/test/utest-Split.cpp
+++ b/libgnucash/engine/test/utest-Split.cpp
@@ -35,7 +35,6 @@ extern "C"
 #include <TransactionP.h>
 #include <gnc-lot.h>
 #include <gnc-event.h>
-#include <qofinstance-p.h>
 
 #if defined(__clang__) && (__clang_major__ == 5 || (__clang_major__ == 3 && __clang_minor__ < 5))
 #define USE_CLANG_FUNC_SIG 1
@@ -45,6 +44,7 @@ static const gchar *suitename = "/engine/Split";
 void test_suite_split ( void );
 }
 
+#include <qofinstance-p.h>
 #include <kvp-frame.hpp>
 
 typedef struct

commit eb6c741bf91f18404007a5d8f2859bd2ecf7caf7
Author: lmat <dartme18 at gmail.com>
Date:   Mon Aug 14 14:32:45 2017 -0400

    Account.c to Account.cpp
    
    Since Account.c is now Account.cpp, the function signatures look a bit
    different internally. The tests rely on function signatures in error
    messages. Instead of trying to figure out what the exact
    function signature might be, I use a substring matching strategy to
    ensure that the correct error was issued.

diff --git a/common/test-core/unittest-support.c b/common/test-core/unittest-support.c
index 86cbe44..dddcef8 100644
--- a/common/test-core/unittest-support.c
+++ b/common/test-core/unittest-support.c
@@ -143,6 +143,29 @@ test_clear_error_list (void)
     message_queue = NULL;
 }
 
+
+gboolean
+test_list_substring_handler (const char *log_domain, GLogLevelFlags log_level,
+                      const gchar *msg, gpointer user_data)
+{
+    GList *list = g_list_first (message_queue);
+    const guint fatal = G_LOG_FLAG_FATAL;
+    while (list)
+    {
+        TestErrorStruct *error = (TestErrorStruct*)list->data;
+        if (!g_strcmp0 (log_domain, error->log_domain)
+                && ((log_level | fatal) == (error->log_level | fatal))
+                && g_strrstr (msg, error->msg))
+        {
+            ++(error->hits);
+            return FALSE;
+        }
+        list = g_list_next (list);
+    }
+    /* No list or no matches, fall through */
+    return test_checked_substring_handler (log_domain, log_level, msg, user_data);
+}
+
 static gboolean
 do_test_list_handler (const char *log_domain, GLogLevelFlags log_level,
                       const gchar *msg, gpointer user_data, gboolean hits)
@@ -206,6 +229,27 @@ do_test_checked_handler (const char *log_domain, GLogLevelFlags log_level,
 }
 
 gboolean
+test_checked_substring_handler (const char *log_domain, GLogLevelFlags log_level,
+                                         const gchar *msg, gpointer user_data)
+{
+    TestErrorStruct *tdata = (TestErrorStruct*)user_data;
+    if ((tdata == NULL)
+            || (tdata->log_domain != NULL
+                && g_strcmp0 (log_domain, tdata->log_domain))
+            || (tdata->log_level && tdata->log_level != log_level)
+            || (tdata->msg && !g_strrstr (msg, tdata->msg)))
+    {
+        gchar *level = test_log_level (log_level);
+        g_printf ( "<%s> (%s) %s\n", level, log_domain, msg);
+        g_free (level);
+        g_assert (log_level ^ G_LOG_FLAG_FATAL);
+        return FALSE;
+    }
+    ++(tdata->hits);
+    return FALSE;
+}
+
+gboolean
 test_checked_handler (const char *log_domain, GLogLevelFlags log_level,
                       const gchar *msg, gpointer user_data )
 {
diff --git a/common/test-core/unittest-support.h b/common/test-core/unittest-support.h
index 61503db..f9e4849 100644
--- a/common/test-core/unittest-support.h
+++ b/common/test-core/unittest-support.h
@@ -179,6 +179,14 @@ GSList *test_log_set_fatal_handler (GSList *list, TestErrorStruct *error,
 void test_free_log_handler (gpointer item);
 
 /**
+ * Check that the user_data error message is a substring of the
+ * actual error otherwise assert.  Displays the error (and asserts
+ * if G_LOG_FLAG_FATAL is TRUE) if NULL is passed as user_data,
+ * but a NULL or 0 value member matches anything.
+ */
+gboolean test_checked_substring_handler (const char *log_domain, GLogLevelFlags log_level,
+                                         const gchar *msg, gpointer user_data);
+/**
  * Check the user_data against the actual error and assert on any
  * differences.  Displays the error (and asserts if G_LOG_FLAG_FATAL
  * is TRUE) if NULL is passed as user_data, but a NULL or 0 value
@@ -215,6 +223,18 @@ void test_clear_error_list (void);
 
 /**
  * Checks received errors against the list created by
+ * test_add_error. Rather than checking for an exact match, this function
+ * checks using a substring match. If the list is empty or nothing
+ * matches, passes control on to test_checked_substring_handler, giving
+ * the opportunity for an additional check that's not in the list
+ * (set user_data to NULL if you want test_checked_handler to
+ * immediately print the error).
+ */
+gboolean test_list_substring_handler (const char *log_domain, GLogLevelFlags log_level,
+                      const gchar *msg, gpointer user_data);
+
+/**
+ * Checks received errors against the list created by
  * test_add_error. If the list is empty or nothing matches, passes
  * control on to test_checked_handler, giving the opportunity for an
  * additional check that's not in the list (set user_data to NULL if
diff --git a/libgnucash/core-utils/gnc-glib-utils.h b/libgnucash/core-utils/gnc-glib-utils.h
index 2999894..a381825 100644
--- a/libgnucash/core-utils/gnc-glib-utils.h
+++ b/libgnucash/core-utils/gnc-glib-utils.h
@@ -39,6 +39,10 @@
 
 #include <glib.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /** @name Character Sets
  @{
 */
@@ -186,6 +190,10 @@ void gnc_gpid_kill(GPid pid);
 
 /** @} */
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
 #endif /* GNC_GLIB_UTILS_H */
 /** @} */
 /** @} */
diff --git a/libgnucash/engine/Account.c b/libgnucash/engine/Account.cpp
similarity index 96%
rename from libgnucash/engine/Account.c
rename to libgnucash/engine/Account.cpp
index bcf5d0a..1b32f9d 100644
--- a/libgnucash/engine/Account.c
+++ b/libgnucash/engine/Account.cpp
@@ -171,7 +171,7 @@ gchar *gnc_account_name_violations_errmsg (const gchar *separator, GList* invali
     for ( node = invalid_account_names;  node; node = g_list_next(node))
     {
         if ( !account_list )
-            account_list = node->data;
+            account_list = static_cast<gchar *>(node->data);
         else
         {
             gchar *tmp_list = NULL;
@@ -251,9 +251,9 @@ gnc_account_init(Account* acc)
     priv->parent   = NULL;
     priv->children = NULL;
 
-    priv->accountName = CACHE_INSERT("");
-    priv->accountCode = CACHE_INSERT("");
-    priv->description = CACHE_INSERT("");
+    priv->accountName = static_cast<char*>(qof_string_cache_insert(""));
+    priv->accountCode = static_cast<char*>(qof_string_cache_insert(""));
+    priv->description = static_cast<char*>(qof_string_cache_insert(""));
 
     priv->type = ACCT_TYPE_NONE;
 
@@ -473,10 +473,10 @@ gnc_account_set_property (GObject         *object,
         break;
     case PROP_TYPE:
         // NEED TO BE CONVERTED TO A G_TYPE_ENUM
-        xaccAccountSetType(account, g_value_get_int(value));
+        xaccAccountSetType(account, static_cast<GNCAccountType>(g_value_get_int(value)));
         break;
     case PROP_COMMODITY:
-        xaccAccountSetCommodity(account, g_value_get_object(value));
+        xaccAccountSetCommodity(account, static_cast<gnc_commodity*>(g_value_get_object(value)));
         break;
     case PROP_COMMODITY_SCU:
         xaccAccountSetCommoditySCU(account, g_value_get_int(value));
@@ -491,19 +491,19 @@ gnc_account_set_property (GObject         *object,
         gnc_account_set_balance_dirty(account);
         break;
     case PROP_START_BALANCE:
-        number = g_value_get_boxed(value);
+        number = static_cast<gnc_numeric*>(g_value_get_boxed(value));
         gnc_account_set_start_balance(account, *number);
         break;
     case PROP_START_CLEARED_BALANCE:
-        number = g_value_get_boxed(value);
+        number = static_cast<gnc_numeric*>(g_value_get_boxed(value));
         gnc_account_set_start_cleared_balance(account, *number);
         break;
     case PROP_START_RECONCILED_BALANCE:
-        number = g_value_get_boxed(value);
+        number = static_cast<gnc_numeric*>(g_value_get_boxed(value));
         gnc_account_set_start_reconciled_balance(account, *number);
         break;
     case PROP_POLICY:
-        gnc_account_set_policy(account, g_value_get_pointer(value));
+        gnc_account_set_policy(account, static_cast<GNCPolicy*>(g_value_get_pointer(value)));
         break;
     case PROP_MARK:
         xaccAccountSetMark(account, g_value_get_int(value));
@@ -595,7 +595,7 @@ gnc_account_class_init (AccountClass *klass)
                           "repeated. but no two accounts that share "
                           "a parent may have the same name.",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -606,7 +606,7 @@ gnc_account_class_init (AccountClass *klass)
                           "all its parent account names to indicate "
                           "a unique account.",
                           NULL,
-                          G_PARAM_READABLE));
+                          static_cast<GParamFlags>(G_PARAM_READABLE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -618,7 +618,7 @@ gnc_account_class_init (AccountClass *klass)
                           "be reporting code that is a synonym for "
                           "the accountName.",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -630,7 +630,7 @@ gnc_account_class_init (AccountClass *klass)
                           "to be a longer, 1-5 sentence description of "
                           "what this account is all about.",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -641,7 +641,7 @@ gnc_account_class_init (AccountClass *klass)
                           "by the user. It is intended to highlight the "
                           "account based on the users wishes.",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -652,7 +652,7 @@ gnc_account_class_init (AccountClass *klass)
                           "for the user to attach any other text that "
                           "they would like to associate with the account.",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -665,7 +665,7 @@ gnc_account_class_init (AccountClass *klass)
                        ACCT_TYPE_NONE,
                        NUM_ACCOUNT_TYPES - 1,
                        ACCT_TYPE_BANK,
-                       G_PARAM_READWRITE));
+                       static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -676,7 +676,7 @@ gnc_account_class_init (AccountClass *klass)
                           "'stuff' stored  in this account, whether "
                           "it is USD, gold, stock, etc.",
                           GNC_TYPE_COMMODITY,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -691,7 +691,7 @@ gnc_account_class_init (AccountClass *klass)
                        0,
                        G_MAXINT32,
                        1000000,
-                       G_PARAM_READWRITE));
+                       static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -704,7 +704,7 @@ gnc_account_class_init (AccountClass *klass)
                            "mismatched values in older versions of "
                            "GnuCash.",
                            FALSE,
-                           G_PARAM_READWRITE));
+                           static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -719,7 +719,7 @@ gnc_account_class_init (AccountClass *klass)
                           "affect the sort order of the account. Note: "
                           "This value can only be set to TRUE.",
                           FALSE,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -733,7 +733,7 @@ gnc_account_class_init (AccountClass *klass)
                           "the engine to say a split has been modified. "
                           "Note: This value can only be set to TRUE.",
                           FALSE,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -749,7 +749,7 @@ gnc_account_class_init (AccountClass *klass)
                         "the 'starting balance' will represent the "
                         "summation of the splits up to that date.",
                         GNC_TYPE_NUMERIC,
-                        G_PARAM_READWRITE));
+                        static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -766,7 +766,7 @@ gnc_account_class_init (AccountClass *klass)
                         "balance' will represent the summation of the "
                         "splits up to that date.",
                         GNC_TYPE_NUMERIC,
-                        G_PARAM_READWRITE));
+                        static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -783,7 +783,7 @@ gnc_account_class_init (AccountClass *klass)
                         "balance' will represent the summation of the "
                         "splits up to that date.",
                         GNC_TYPE_NUMERIC,
-                        G_PARAM_READWRITE));
+                        static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -818,7 +818,7 @@ gnc_account_class_init (AccountClass *klass)
                         "the starting balance and all reconciled splits "
                         "in the account.",
                         GNC_TYPE_NUMERIC,
-                        G_PARAM_READABLE));
+                        static_cast<GParamFlags>(G_PARAM_READABLE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -826,7 +826,7 @@ gnc_account_class_init (AccountClass *klass)
      g_param_spec_pointer ("policy",
                            "Policy",
                            "The account lots policy.",
-                           G_PARAM_READWRITE));
+                           static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -837,7 +837,7 @@ gnc_account_class_init (AccountClass *klass)
                        0,
                        G_MAXINT16,
                        0,
-                       G_PARAM_READWRITE));
+                       static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -847,7 +847,7 @@ gnc_account_class_init (AccountClass *klass)
                            "Whether the account maps to an entry on an "
                            "income tax document.",
                            FALSE,
-                           G_PARAM_READWRITE));
+                           static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -859,7 +859,7 @@ gnc_account_class_init (AccountClass *klass)
                           "United States it is used to transfer totals "
                           "into tax preparation software.",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -868,7 +868,7 @@ gnc_account_class_init (AccountClass *klass)
                           "Tax Source",
                           "This specifies where exported name comes from.",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -880,7 +880,7 @@ gnc_account_class_init (AccountClass *klass)
                          (gint64)1,
                          G_MAXINT64,
                          (gint64)1,
-                         G_PARAM_READWRITE));
+                         static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -890,7 +890,7 @@ gnc_account_class_init (AccountClass *klass)
                            "Whether the account should be hidden in the  "
                            "account tree.",
                            FALSE,
-                           G_PARAM_READWRITE));
+                           static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -900,7 +900,7 @@ gnc_account_class_init (AccountClass *klass)
                            "Whether the account is a placeholder account which does not "
                            "allow transactions to be created, edited or deleted.",
                            FALSE,
-                           G_PARAM_READWRITE));
+                           static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -910,7 +910,7 @@ gnc_account_class_init (AccountClass *klass)
                           "The account filter is a value saved to allow "
                           "filters to be recalled.",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -920,7 +920,7 @@ gnc_account_class_init (AccountClass *klass)
                           "The account sort order is a value saved to allow "
                           "the sort order to be recalled.",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -929,7 +929,7 @@ gnc_account_class_init (AccountClass *klass)
                           "Account Sort Reversed",
                           "Parameter to store whether the sort order is reversed or not.",
                           FALSE,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -940,7 +940,7 @@ gnc_account_class_init (AccountClass *klass)
                          (gint64)1,
                          G_MAXINT64,
                          (gint64)1,
-                         G_PARAM_READWRITE));
+                         static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -950,7 +950,7 @@ gnc_account_class_init (AccountClass *klass)
                           "The online account which corresponds to this "
                           "account for OFX import",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
      g_object_class_install_property(
        gobject_class,
@@ -959,7 +959,7 @@ gnc_account_class_init (AccountClass *klass)
                            "Associated income account",
                            "Used by the OFX importer.",
                            GNC_TYPE_GUID,
-                           G_PARAM_READWRITE));
+                           static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -969,7 +969,7 @@ gnc_account_class_init (AccountClass *klass)
                           "The AqBanking account which corresponds to this "
                           "account for AQBanking import",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
     g_object_class_install_property
     (gobject_class,
      PROP_AB_BANK_CODE,
@@ -978,7 +978,7 @@ gnc_account_class_init (AccountClass *klass)
                           "The online account which corresponds to this "
                           "account for AQBanking import",
                           NULL,
-                          G_PARAM_READWRITE));
+                          static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -989,7 +989,7 @@ gnc_account_class_init (AccountClass *klass)
                          (gint64)1,
                          G_MAXINT64,
                          (gint64)1,
-                         G_PARAM_READWRITE));
+                         static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
     g_object_class_install_property
     (gobject_class,
@@ -999,7 +999,7 @@ gnc_account_class_init (AccountClass *klass)
                         "The time of the last transaction retrieval for this "
                         "account.",
                         GNC_TYPE_TIMESPEC,
-                        G_PARAM_READWRITE));
+                        static_cast<GParamFlags>(G_PARAM_READWRITE)));
 
 }
 
@@ -1028,7 +1028,7 @@ static Account *
 gnc_coll_get_root_account (QofCollection *col)
 {
     if (!col) return NULL;
-    return qof_collection_get_data (col);
+    return static_cast<Account*>(qof_collection_get_data (col));
 }
 
 static void
@@ -1101,7 +1101,7 @@ xaccMallocAccount (QofBook *book)
 
     g_return_val_if_fail (book, NULL);
 
-    acc = g_object_new (GNC_TYPE_ACCOUNT, NULL);
+    acc = static_cast<Account*>(g_object_new (GNC_TYPE_ACCOUNT, NULL));
     xaccInitAccount (acc, book);
     qof_event_gen (&acc->inst, QOF_EVENT_CREATE, NULL);
 
@@ -1118,7 +1118,7 @@ gnc_account_create_root (QofBook *book)
     rpriv = GET_PRIVATE(root);
     xaccAccountBeginEdit(root);
     rpriv->type = ACCT_TYPE_ROOT;
-    CACHE_REPLACE(rpriv->accountName, "Root Account");
+    qof_string_cache_replace((void const **)(&rpriv->accountName), "Root Account");
     mark_account (root);
     xaccAccountCommitEdit(root);
     gnc_book_set_root_account(book, root);
@@ -1135,7 +1135,7 @@ xaccCloneAccount(const Account *from, QofBook *book)
     g_return_val_if_fail(QOF_IS_BOOK(book), NULL);
 
     ENTER (" ");
-    ret = g_object_new (GNC_TYPE_ACCOUNT, NULL);
+    ret = static_cast<Account*>(g_object_new (GNC_TYPE_ACCOUNT, NULL));
     g_return_val_if_fail (ret, NULL);
 
     from_priv = GET_PRIVATE(from);
@@ -1147,9 +1147,9 @@ xaccCloneAccount(const Account *from, QofBook *book)
      * Also let caller issue the generate_event (EVENT_CREATE) */
     priv->type = from_priv->type;
 
-    priv->accountName = CACHE_INSERT(from_priv->accountName);
-    priv->accountCode = CACHE_INSERT(from_priv->accountCode);
-    priv->description = CACHE_INSERT(from_priv->description);
+    priv->accountName = static_cast<char*>(qof_string_cache_insert(from_priv->accountName));
+    priv->accountCode = static_cast<char*>(qof_string_cache_insert(from_priv->accountCode));
+    priv->description = static_cast<char*>(qof_string_cache_insert(from_priv->description));
 
     qof_instance_copy_kvp (QOF_INSTANCE (ret), QOF_INSTANCE (from));
 
@@ -1229,7 +1229,7 @@ xaccFreeAccount (Account *acc)
 
         for (lp = priv->lots; lp; lp = lp->next)
         {
-            GNCLot *lot = lp->data;
+            GNCLot *lot = static_cast<GNCLot*>(lp->data);
             gnc_lot_destroy (lot);
         }
         g_list_free (priv->lots);
@@ -1261,15 +1261,16 @@ xaccFreeAccount (Account *acc)
 */
     }
 
-    CACHE_REPLACE(priv->accountName, NULL);
-    CACHE_REPLACE(priv->accountCode, NULL);
-    CACHE_REPLACE(priv->description, NULL);
+    qof_string_cache_remove(priv->accountName);
+    qof_string_cache_remove(priv->accountCode);
+    qof_string_cache_remove(priv->description);
+    priv->accountName = priv->accountCode = priv->description = nullptr;
 
     /* zero out values, just in case stray
      * pointers are pointing here. */
 
-    priv->parent = NULL;
-    priv->children = NULL;
+    priv->parent = nullptr;
+    priv->children = nullptr;
 
     priv->balance  = gnc_numeric_zero();
     priv->cleared_balance = gnc_numeric_zero();
@@ -1327,7 +1328,7 @@ destroy_pending_splits_for_account(QofInstance *ent, gpointer acc)
     Split *split;
 
     if (xaccTransIsOpen(trans))
-        while ((split = xaccTransFindSplitByAccount(trans, acc)))
+        while ((split = xaccTransFindSplitByAccount(trans, static_cast<Account*>(acc))))
             xaccSplitDestroy(split);
 }
 
@@ -1365,7 +1366,7 @@ xaccAccountCommitEdit (Account *acc)
             slist = g_list_copy(priv->splits);
             for (lp = slist; lp; lp = lp->next)
             {
-                Split *s = lp->data;
+                Split *s = static_cast<Split *>(lp->data);
                 xaccSplitDestroy (s);
             }
             g_list_free(slist);
@@ -1392,7 +1393,7 @@ xaccAccountCommitEdit (Account *acc)
             /* the lots should be empty by now */
             for (lp = priv->lots; lp; lp = lp->next)
             {
-                GNCLot *lot = lp->data;
+                GNCLot *lot = static_cast<GNCLot*>(lp->data);
                 gnc_lot_destroy (lot);
             }
         }
@@ -1455,7 +1456,7 @@ xaccAcctChildrenEqual(const GList *na,
 
     while (na)
     {
-        Account *aa = na->data;
+        Account *aa = static_cast<Account*>(na->data);
         Account *ab;
         GList *node = g_list_find_custom ((GList*)nb, aa,
                                           (GCompareFunc)compare_account_by_name);
@@ -1465,7 +1466,7 @@ xaccAcctChildrenEqual(const GList *na,
             PINFO ("Unable to find matching child account.");
             return FALSE;
         }
-        ab = node->data;
+        ab = static_cast<Account*>(node->data);
         if (!xaccAccountEqual(aa, ab, check_guids))
         {
             char sa[GUID_ENCODING_LENGTH + 1];
@@ -1883,7 +1884,7 @@ xaccClearMarkDown (Account *acc, short val)
     priv->mark = val;
     for (node = priv->children; node; node = node->next)
     {
-        xaccClearMarkDown(node->data, val);
+        xaccClearMarkDown(static_cast<Account*>(node->data), val);
     }
 }
 
@@ -2254,7 +2255,7 @@ xaccAccountSetName (Account *acc, const char *str)
         return;
 
     xaccAccountBeginEdit(acc);
-    CACHE_REPLACE(priv->accountName, str);
+    qof_string_cache_replace((void const **)(&priv->accountName), str);
     mark_account (acc);
     xaccAccountCommitEdit(acc);
 }
@@ -2273,7 +2274,7 @@ xaccAccountSetCode (Account *acc, const char *str)
         return;
 
     xaccAccountBeginEdit(acc);
-    CACHE_REPLACE(priv->accountCode, str ? str : "");
+    qof_string_cache_replace((void const **)(&priv->accountCode), str ? str : "");
     mark_account (acc);
     xaccAccountCommitEdit(acc);
 }
@@ -2292,7 +2293,7 @@ xaccAccountSetDescription (Account *acc, const char *str)
         return;
 
     xaccAccountBeginEdit(acc);
-    CACHE_REPLACE(priv->description, str ? str : "");
+    qof_string_cache_replace((void const **)(&priv->description), str ? str : "");
     mark_account (acc);
     xaccAccountCommitEdit(acc);
 }
@@ -2691,7 +2692,7 @@ Account *
 gnc_account_nth_child (const Account *parent, gint num)
 {
     g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL);
-    return g_list_nth_data(GET_PRIVATE(parent)->children, num);
+    return static_cast<Account*>(g_list_nth_data(GET_PRIVATE(parent)->children, num));
 }
 
 gint
@@ -2706,7 +2707,7 @@ gnc_account_n_descendants (const Account *account)
     priv = GET_PRIVATE(account);
     for (node = priv->children; node; node = g_list_next(node))
     {
-        count += gnc_account_n_descendants(node->data) + 1;
+        count += gnc_account_n_descendants(static_cast<Account*>(node->data)) + 1;
     }
     return count;
 }
@@ -2745,7 +2746,7 @@ gnc_account_get_tree_depth (const Account *account)
 
     for (node = priv->children; node; node = g_list_next(node))
     {
-        child_depth = gnc_account_get_tree_depth(node->data);
+        child_depth = gnc_account_get_tree_depth(static_cast<Account const *>(node->data));
         depth = MAX(depth, child_depth);
     }
     return depth + 1;
@@ -2768,7 +2769,7 @@ gnc_account_get_descendants (const Account *account)
     {
         descendants = g_list_append(descendants, child->data);
         descendants = g_list_concat(descendants,
-                                    gnc_account_get_descendants(child->data));
+                gnc_account_get_descendants(static_cast<Account const *>(child->data)));
     }
     return descendants;
 }
@@ -2793,7 +2794,7 @@ gnc_account_get_descendants_sorted (const Account *account)
     {
         descendants = g_list_append(descendants, child->data);
         descendants = g_list_concat(descendants,
-                                    gnc_account_get_descendants_sorted(child->data));
+                gnc_account_get_descendants_sorted(static_cast<Account const *>(child->data)));
     }
     g_list_free(children);
     return descendants;
@@ -2813,7 +2814,7 @@ gnc_account_lookup_by_name (const Account *parent, const char * name)
     ppriv = GET_PRIVATE(parent);
     for (node = ppriv->children; node; node = node->next)
     {
-        child = node->data;
+        child = static_cast<Account*>(node->data);
         cpriv = GET_PRIVATE(child);
         if (g_strcmp0(cpriv->accountName, name) == 0)
             return child;
@@ -2823,7 +2824,7 @@ gnc_account_lookup_by_name (const Account *parent, const char * name)
      * Recursively search each of the child accounts next */
     for (node = ppriv->children; node; node = node->next)
     {
-        child = node->data;
+        child = static_cast<Account*>(node->data);
         result = gnc_account_lookup_by_name (child, name);
         if (result)
             return result;
@@ -2846,7 +2847,7 @@ gnc_account_lookup_by_code (const Account *parent, const char * code)
     ppriv = GET_PRIVATE(parent);
     for (node = ppriv->children; node; node = node->next)
     {
-        child = node->data;
+        child = static_cast<Account*>(node->data);
         cpriv = GET_PRIVATE(child);
         if (g_strcmp0(cpriv->accountCode, code) == 0)
             return child;
@@ -2856,7 +2857,7 @@ gnc_account_lookup_by_code (const Account *parent, const char * code)
      * Recursively search each of the child accounts next */
     for (node = ppriv->children; node; node = node->next)
     {
-        child = node->data;
+        child = static_cast<Account*>(node->data);
         result = gnc_account_lookup_by_code (child, code);
         if (result)
             return result;
@@ -2884,7 +2885,7 @@ gnc_account_lookup_by_full_name_helper (const Account *parent,
     ppriv = GET_PRIVATE(parent);
     for (node = ppriv->children; node; node = node->next)
     {
-        Account *account = node->data;
+        Account *account = static_cast<Account*>(node->data);
 
         priv = GET_PRIVATE(account);
         if (g_strcmp0(priv->accountName, names[0]) == 0)
@@ -2950,7 +2951,7 @@ gnc_account_foreach_child (const Account *acc,
     priv = GET_PRIVATE(acc);
     for (node = priv->children; node; node = node->next)
     {
-        thunk (node->data, user_data);
+        thunk (static_cast<Account*>(node->data), user_data);
     }
 }
 
@@ -2969,7 +2970,7 @@ gnc_account_foreach_descendant (const Account *acc,
     priv = GET_PRIVATE(acc);
     for (node = priv->children; node; node = node->next)
     {
-        child = node->data;
+        child = static_cast<Account*>(node->data);
         thunk(child, user_data);
         gnc_account_foreach_descendant(child, thunk, user_data);
     }
@@ -2991,7 +2992,7 @@ gnc_account_foreach_descendant_until (const Account *acc,
     priv = GET_PRIVATE(acc);
     for (node = priv->children; node; node = node->next)
     {
-        child = node->data;
+        child = static_cast<Account*>(node->data);
         result = thunk(child, user_data);
         if (result)
             return(result);
@@ -3040,7 +3041,6 @@ gnc_account_get_full_name(const Account *account)
     AccountPrivate *priv;
     const Account *a;
     char *fullname;
-    gchar **names;
     int level;
 
     /* So much for hardening the API. Too many callers to this function don't
@@ -3067,7 +3067,7 @@ gnc_account_get_full_name(const Account *account)
 
     /* Get all the pointers in the right order. The root node "entry"
      * becomes the terminating NULL pointer for the array of strings. */
-    names = g_malloc(level * sizeof(gchar *));
+    gchar* names[level*sizeof(gchar*)];
     names[--level] = NULL;
     for (a = account; level > 0; a = priv->parent)
     {
@@ -3077,7 +3077,6 @@ gnc_account_get_full_name(const Account *account)
 
     /* Build the full name */
     fullname =  g_strjoinv(account_separator, names);
-    g_free(names);
 
     return fullname;
 }
@@ -3267,7 +3266,7 @@ xaccAccountGetProjectedMinimumBalance (const Account *acc)
     today = gnc_time64_get_today_end();
     for (node = g_list_last(priv->splits); node; node = node->prev)
     {
-        Split *split = node->data;
+        Split *split = static_cast<Split*>(node->data);
 
         if (!seen_a_transaction)
         {
@@ -3383,7 +3382,7 @@ xaccAccountGetPresentBalance (const Account *acc)
     today = gnc_time64_get_today_end();
     for (node = g_list_last(priv->splits); node; node = node->prev)
     {
-        Split *split = node->data;
+        Split *split = static_cast<Split*>(node->data);
 
         if (xaccTransGetDate (xaccSplitGetParent (split)) <= today)
             return xaccSplitGetBalance (split);
@@ -3517,7 +3516,7 @@ typedef struct
 static void
 xaccAccountBalanceHelper (Account *acc, gpointer data)
 {
-    CurrencyBalance *cb = data;
+    CurrencyBalance *cb = static_cast<CurrencyBalance*>(data);
     gnc_numeric balance;
 
     if (!cb->fn || !cb->currency)
@@ -3531,7 +3530,7 @@ xaccAccountBalanceHelper (Account *acc, gpointer data)
 static void
 xaccAccountBalanceAsOfDateHelper (Account *acc, gpointer data)
 {
-    CurrencyBalance *cb = data;
+    CurrencyBalance *cb = static_cast<CurrencyBalance*>(data);
     gnc_numeric balance;
 
     g_return_if_fail (cb->asOfDateFn && cb->currency);
@@ -3768,7 +3767,7 @@ xaccAccountFindOpenLots (const Account *acc,
     priv = GET_PRIVATE(acc);
     for (lot_list = priv->lots; lot_list; lot_list = lot_list->next)
     {
-        GNCLot *lot = lot_list->data;
+        GNCLot *lot = static_cast<GNCLot*>(lot_list->data);
 
         /* If this lot is closed, then ignore it */
         if (gnc_lot_is_closed (lot))
@@ -4111,7 +4110,7 @@ xaccAccountStringToEnum(const char* str)
 /********************************************************************\
 \********************************************************************/
 
-static char *
+static char const *
 account_type_name[NUM_ACCOUNT_TYPES] =
 {
     N_("Bank"),
@@ -4763,7 +4762,7 @@ finder_help_function(const Account *acc, const char *description,
     priv = GET_PRIVATE(acc);
     for (slp = g_list_last(priv->splits); slp; slp = slp->prev)
     {
-        Split *lsplit = slp->data;
+        Split *lsplit = static_cast<Split*>(slp->data);
         Transaction *ltrans = xaccSplitGetParent(lsplit);
 
         if (g_strcmp0 (description, xaccTransGetDescription (ltrans)) == 0)
@@ -4821,7 +4820,7 @@ gnc_account_join_children (Account *to_parent, Account *from_parent)
     ENTER (" ");
     children = g_list_copy(from_priv->children);
     for (node = children; node; node = g_list_next(node))
-        gnc_account_append_child(to_parent, node->data);
+        gnc_account_append_child(to_parent, static_cast <Account*> (node->data));
     g_list_free(children);
     LEAVE (" ");
 }
@@ -4839,12 +4838,12 @@ gnc_account_merge_children (Account *parent)
     ppriv = GET_PRIVATE(parent);
     for (node_a = ppriv->children; node_a; node_a = node_a->next)
     {
-        Account *acc_a = node_a->data;
+        Account *acc_a = static_cast <Account*> (node_a->data);
 
         priv_a = GET_PRIVATE(acc_a);
         for (node_b = node_a->next; node_b; node_b = g_list_next(node_b))
         {
-            Account *acc_b = node_b->data;
+            Account *acc_b = static_cast <Account*> (node_b->data);
 
             priv_b = GET_PRIVATE(acc_b);
             if (0 != null_strcmp(priv_a->accountName, priv_b->accountName))
@@ -4881,7 +4880,7 @@ gnc_account_merge_children (Account *parent)
 
             /* consolidate transactions */
             while (priv_b->splits)
-                xaccSplitSetAccount (priv_b->splits->data, acc_a);
+                xaccSplitSetAccount (static_cast <Split*> (priv_b->splits->data), acc_a);
 
             /* move back one before removal. next iteration around the loop
              * will get the node after node_b */
@@ -4906,7 +4905,7 @@ xaccSplitsBeginStagedTransactionTraversals (GList *splits)
 
     for (lp = splits; lp; lp = lp->next)
     {
-        Split *s = lp->data;
+        Split *s = static_cast <Split*> (lp->data);
         Transaction *trans = s->parent;
 
         if (trans)
@@ -4987,7 +4986,7 @@ xaccAccountStagedTransactionTraversal (const Account *acc,
          * a thunk removes splits from this account. */
         next = g_list_next(split_p);
 
-        s = split_p->data;
+        s = static_cast <Split*> (split_p->data);
         trans = s->parent;
         if (trans && (trans->marker < stage))
         {
@@ -5021,15 +5020,15 @@ gnc_account_tree_staged_transaction_traversal (const Account *acc,
     priv = GET_PRIVATE(acc);
     for (acc_p = priv->children; acc_p; acc_p = g_list_next(acc_p))
     {
-        retval = gnc_account_tree_staged_transaction_traversal(acc_p->data, stage,
-                 thunk, cb_data);
+        retval = gnc_account_tree_staged_transaction_traversal(static_cast <Account*> (acc_p->data),
+                stage, thunk, cb_data);
         if (retval) return retval;
     }
 
     /* Now this account */
     for (split_p = priv->splits; split_p; split_p = g_list_next(split_p))
     {
-        s = split_p->data;
+        s = static_cast <Split*> (split_p->data);
         trans = s->parent;
         if (trans && (trans->marker < stage))
         {
@@ -5294,7 +5293,7 @@ highestProbability(gpointer key, gpointer value, gpointer data)
     {
         /* Save the new highest probability and the assoaciated account guid */
         account_i->probability = GPOINTER_TO_INT(value);
-        account_i->account_guid = key;
+        account_i->account_guid = static_cast <char*> (key);
     }
 }
 
@@ -5370,8 +5369,8 @@ gnc_account_imap_find_account_bayes (GncImportMatchMap *imap, GList *tokens)
                   account_c->account_guid, account_c->token_count,
                   tokenInfo.total_count);
 
-            account_p = g_hash_table_lookup(running_probabilities,
-                                            account_c->account_guid);
+            account_p = static_cast <account_probability*> (
+                    g_hash_table_lookup(running_probabilities, account_c->account_guid));
 
             /* if the account exists in the list then continue
              * the running probablities
@@ -5612,7 +5611,7 @@ build_bayes_layer_two (const char *key, const GValue *value, gpointer user_data)
 
     g_free (guid);
 
-    imapInfo_node = g_malloc(sizeof(*imapInfo_node));
+    imapInfo_node = static_cast <imap_info*> (g_malloc(sizeof(*imapInfo_node)));
 
     imapInfo_node->source_account = imapInfo->source_account;
     imapInfo_node->map_account    = map_account;
@@ -5688,7 +5687,7 @@ build_non_bayes (const char *key, const GValue *value, gpointer user_data)
 
         PINFO("build_non_bayes: kvp_path is '%s'", kvp_path);
 
-        imapInfo_node = g_malloc(sizeof(*imapInfo_node));
+        imapInfo_node = static_cast <imap_info*> (g_malloc(sizeof(*imapInfo_node)));
 
         imapInfo_node->source_account = imapInfo->source_account;
         imapInfo_node->map_account    = xaccAccountLookup (guid, book);
@@ -5810,7 +5809,7 @@ look_for_old_separator_descendants (Account *root, gchar *full_name, const gchar
     /* Go through list of top level accounts */
     for (ptr = top_accounts; ptr; ptr = g_list_next (ptr))
     {
-        const gchar *name = xaccAccountGetName (ptr->data);
+        const gchar *name = xaccAccountGetName (static_cast <Account const *> (ptr->data));
 
         // we are looking for the longest top level account that matches
         if (g_str_has_prefix (full_name, name))
@@ -5935,7 +5934,7 @@ convert_imap_account (Account *acc)
         for (node = imap_list;  node; node = g_list_next (node))
         {
             Account *map_account = NULL;
-            GncImapInfo *imapInfo = node->data;
+            GncImapInfo *imapInfo = static_cast <GncImapInfo *> (node->data);
 
             // Lets start doing stuff
             map_account = look_for_old_mapping (imapInfo);
@@ -5980,7 +5979,7 @@ gnc_account_imap_convert_bayes (QofBook *book)
         /* Go through list of accounts */
         for (ptr = accts; ptr; ptr = g_list_next (ptr))
         {
-            Account *acc = ptr->data;
+            Account *acc = static_cast <Account*> (ptr->data);
 
             convert_imap_account (acc);
         }
@@ -6020,7 +6019,7 @@ static QofObject account_object_def =
     DI(.interface_version = ) QOF_OBJECT_VERSION,
     DI(.e_type            = ) GNC_ID_ACCOUNT,
     DI(.type_label        = ) "Account",
-    DI(.create            = ) (gpointer)xaccMallocAccount,
+    DI(.create            = ) (void*(*)(QofBook*)) xaccMallocAccount,
     DI(.book_begin        = ) NULL,
     DI(.book_end          = ) gnc_account_book_end,
     DI(.is_dirty          = ) qof_collection_is_dirty,
diff --git a/libgnucash/engine/Account.h b/libgnucash/engine/Account.h
index 13f265c..2f80632 100644
--- a/libgnucash/engine/Account.h
+++ b/libgnucash/engine/Account.h
@@ -48,6 +48,9 @@
 #include "gnc-engine.h"
 #include "policy.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 typedef gnc_numeric (*xaccGetBalanceFn)( const Account *account );
 
 typedef gnc_numeric (*xaccGetBalanceInCurrencyFn) (
@@ -1517,6 +1520,10 @@ const char * dxaccAccountGetQuoteTZ (const Account *account);
  * in the gnome-search parameter list.  Be careful when you use this. */
 #define ACCOUNT_MATCH_ALL_TYPE	"account-match-all"
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
 #endif /* XACC_ACCOUNT_H */
 /** @} */
 /** @} */
diff --git a/libgnucash/engine/AccountP.h b/libgnucash/engine/AccountP.h
index a3a2bdd..a1ab6a0 100644
--- a/libgnucash/engine/AccountP.h
+++ b/libgnucash/engine/AccountP.h
@@ -41,6 +41,10 @@
 
 #include "Account.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define GNC_ID_ROOT_ACCOUNT        "RootAccount"
 
 /** STRUCTS *********************************************************/
@@ -149,5 +153,8 @@ typedef struct
 
 AccountTestFunctions* _utest_account_fill_functions(void);
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
 
 #endif /* XACC_ACCOUNT_P_H */
diff --git a/libgnucash/engine/CMakeLists.txt b/libgnucash/engine/CMakeLists.txt
index eeeb7f9..993eb5e 100644
--- a/libgnucash/engine/CMakeLists.txt
+++ b/libgnucash/engine/CMakeLists.txt
@@ -136,7 +136,7 @@ ADD_CUSTOM_COMMAND (
 ADD_CUSTOM_TARGET(iso-4217-c DEPENDS ${ISO_4217_C})
 
 SET (engine_SOURCES
-  Account.c
+  Account.cpp
   Recurrence.c
   Query.c
   SchedXaction.c
diff --git a/libgnucash/engine/Makefile.am b/libgnucash/engine/Makefile.am
index 49c70cc..088b9b4 100644
--- a/libgnucash/engine/Makefile.am
+++ b/libgnucash/engine/Makefile.am
@@ -18,7 +18,7 @@ AM_CPPFLAGS = \
 
 
 libgncmod_engine_la_SOURCES = \
-  Account.c \
+  Account.cpp \
   Recurrence.c \
   Query.c \
   SchedXaction.c \
diff --git a/libgnucash/engine/Split.h b/libgnucash/engine/Split.h
index 1c45080..4d7f417 100644
--- a/libgnucash/engine/Split.h
+++ b/libgnucash/engine/Split.h
@@ -41,6 +41,10 @@ typedef struct _SplitClass SplitClass;
 #include "gnc-commodity.h"
 #include "gnc-engine.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* --- type macros --- */
 #define GNC_TYPE_SPLIT            (gnc_split_get_type ())
 #define GNC_SPLIT(o)              \
@@ -550,6 +554,10 @@ gnc_numeric xaccSplitVoidFormerValue(const Split *split);
 /** \deprecated */
 #define xaccSplitReturnGUID(X) (X ? *(qof_entity_get_guid(QOF_INSTANCE(X))) : *(guid_null()))
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
 #endif /* XACC_SPLIT_H */
 /** @} */
 /** @} */
diff --git a/libgnucash/engine/Transaction.h b/libgnucash/engine/Transaction.h
index a196e89..2d14389 100644
--- a/libgnucash/engine/Transaction.h
+++ b/libgnucash/engine/Transaction.h
@@ -94,6 +94,10 @@ typedef struct _TransactionClass TransactionClass;
 #include "gnc-engine.h"
 #include "Split.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* --- type macros --- */
 #define GNC_TYPE_TRANSACTION            (gnc_transaction_get_type ())
 #define GNC_TRANSACTION(o)              \
@@ -789,6 +793,10 @@ void xaccTransDump (const Transaction *trans, const char *tag);
 /** \deprecated */
 #define xaccTransReturnGUID(X) (X ? *(qof_entity_get_guid(QOF_INSTANCE(X))) : *(guid_null()))
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
 #endif /* XACC_TRANSACTION_H */
 /** @} */
 /** @} */
diff --git a/libgnucash/engine/gnc-commodity.h b/libgnucash/engine/gnc-commodity.h
index 8daa83b..b5dcc93 100644
--- a/libgnucash/engine/gnc-commodity.h
+++ b/libgnucash/engine/gnc-commodity.h
@@ -53,6 +53,10 @@ typedef struct _GncCommodityNamespaceClass gnc_commodity_namespaceClass;
 #include <glib/gi18n.h>
 #include "gnc-engine.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* --- type macros --- */
 #define GNC_TYPE_COMMODITY            (gnc_commodity_get_type ())
 #define GNC_COMMODITY(o)              \
@@ -1056,6 +1060,10 @@ void gnc_monetary_list_free(MonetaryList *list);
 
 /** @} */
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
 #endif /* GNC_COMMODITY_H */
 /** @} */
 /** @} */
diff --git a/libgnucash/engine/gnc-engine.h b/libgnucash/engine/gnc-engine.h
index f8f1c98..651cf44 100644
--- a/libgnucash/engine/gnc-engine.h
+++ b/libgnucash/engine/gnc-engine.h
@@ -39,6 +39,10 @@
 #include <glib.h>
 #include "qof.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /** \name QofLogModule identifiers */
 // @{
 #define GNC_MOD_ROOT      "gnc"
@@ -257,6 +261,9 @@ void gnc_engine_signal_commit_error( QofBackendError errcode );
 #define GNC_OWNER_GUID    "owner-guid"
 #define GNC_SX_ID         "sched-xaction"
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
 
 #endif
 /** @} */
diff --git a/libgnucash/engine/gnc-features.h b/libgnucash/engine/gnc-features.h
index 39f1c03..feefe8d 100644
--- a/libgnucash/engine/gnc-features.h
+++ b/libgnucash/engine/gnc-features.h
@@ -38,6 +38,10 @@
 
 #include "qof.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /** @name Defined features
 @{
  */
@@ -64,6 +68,10 @@ gchar *gnc_features_test_unknown (QofBook *book);
  */
 void gnc_features_set_used (QofBook *book, const gchar *feature);
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
 #endif /* GNC_FEATURES_H */
 /** @} */
 /** @} */
diff --git a/libgnucash/engine/gnc-lot.h b/libgnucash/engine/gnc-lot.h
index 64e1dfa..c725b6f 100644
--- a/libgnucash/engine/gnc-lot.h
+++ b/libgnucash/engine/gnc-lot.h
@@ -65,6 +65,10 @@
 #include "gnc-engine.h"
 /*#include "gnc-lot-p.h"*/
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct
 {
     QofInstanceClass parent_class;
@@ -174,6 +178,11 @@ GNCLot * gnc_lot_make_default (Account * acc);
 #define LOT_BALANCE     "balance"
 #define LOT_TITLE       "lot-title"
 #define LOT_NOTES       "notes"
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
 #endif /* GNC_LOT_H */
 /** @} */
 /** @} */
diff --git a/libgnucash/engine/gnc-pricedb.h b/libgnucash/engine/gnc-pricedb.h
index f7eefa3..671c87e 100644
--- a/libgnucash/engine/gnc-pricedb.h
+++ b/libgnucash/engine/gnc-pricedb.h
@@ -31,6 +31,10 @@ typedef struct _GncPriceDBClass GNCPriceDBClass;
 #include "gnc-commodity.h"
 #include "gnc-engine.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* --- type macros --- */
 #define GNC_TYPE_PRICE            (gnc_price_get_type ())
 #define GNC_PRICE(o)              \
@@ -662,6 +666,10 @@ void gnc_pricedb_print_contents(GNCPriceDB *db, FILE *f);
 
 /** @} */
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
 #endif /* GNC_PRICEDB_H */
 /** @} */
 /** @} */
diff --git a/libgnucash/engine/policy.h b/libgnucash/engine/policy.h
index 42dc812..71e4c0ed 100644
--- a/libgnucash/engine/policy.h
+++ b/libgnucash/engine/policy.h
@@ -37,6 +37,10 @@
 #ifndef XACC_POLICY_H
 #define XACC_POLICY_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct gncpolicy_s GNCPolicy;
 
 /** Valid Policy List
@@ -83,6 +87,10 @@ GNCPolicy *xaccGetFIFOPolicy (void);
  */
 GNCPolicy *xaccGetLIFOPolicy (void);
 
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
 #endif /* XACC_POLICY_H */
 /** @} */
 /** @} */
diff --git a/libgnucash/engine/qof-string-cache.cpp b/libgnucash/engine/qof-string-cache.cpp
index 70e79d7..7390a63 100644
--- a/libgnucash/engine/qof-string-cache.cpp
+++ b/libgnucash/engine/qof-string-cache.cpp
@@ -132,4 +132,11 @@ qof_string_cache_insert(gconstpointer key)
     return NULL;
 }
 
+void
+qof_string_cache_replace(gconstpointer * dst, gconstpointer src)
+{
+    gpointer tmp {qof_string_cache_insert(src)};
+    qof_string_cache_remove(&dst);
+    *dst = tmp;
+}
 /* ************************ END OF FILE ***************************** */
diff --git a/libgnucash/engine/qof-string-cache.h b/libgnucash/engine/qof-string-cache.h
index 4aaa485..2fd5274 100644
--- a/libgnucash/engine/qof-string-cache.h
+++ b/libgnucash/engine/qof-string-cache.h
@@ -86,6 +86,10 @@ void qof_string_cache_remove(gconstpointer key);
 */
 gpointer qof_string_cache_insert(gconstpointer key);
 
+/** Same as CACHE_REPLACE below, but safe to call from C++.
+ */
+void qof_string_cache_replace(gconstpointer * dst, gconstpointer src);
+
 #define CACHE_INSERT(str) qof_string_cache_insert((gconstpointer)(str))
 #define CACHE_REMOVE(str) qof_string_cache_remove((str))
 
diff --git a/libgnucash/engine/test/utest-Account.cpp b/libgnucash/engine/test/utest-Account.cpp
index 06dae62..3007907 100644
--- a/libgnucash/engine/test/utest-Account.cpp
+++ b/libgnucash/engine/test/utest-Account.cpp
@@ -467,13 +467,7 @@ test_gnc_account_list_name_violations (Fixture *fixture, gconstpointer pData)
 {
     auto log_level = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
     auto log_domain = "gnc.engine";
-#ifdef USE_CLANG_FUNC_SIG
-#define _func "GList *gnc_account_list_name_violations(QofBook *, const gchar *)"
-#else
-#define _func "gnc_account_list_name_violations"
-#endif
-    auto msg = _func ": assertion 'separator != NULL' failed";
-#undef _func
+    auto msg = ": assertion 'separator != NULL' failed";
     auto check = test_error_struct_new(log_domain, log_level, msg);
     GList *results, *res_iter;
     auto sep = ":";
@@ -482,7 +476,7 @@ test_gnc_account_list_name_violations (Fixture *fixture, gconstpointer pData)
      * affect the test_log_fatal_handler
      */
     GLogFunc oldlogger = g_log_set_default_handler ((GLogFunc)test_null_handler, check);
-    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler, check);
+    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_substring_handler, check);
     g_assert (gnc_account_list_name_violations (NULL, NULL) == NULL);
     g_assert_cmpint (check->hits, ==, 1);
     g_assert (gnc_account_list_name_violations (book, NULL) == NULL);
@@ -759,19 +753,13 @@ test_xaccCloneAccount (Fixture *fixture, gconstpointer pData)
     Account *clone;
     QofBook *book = gnc_account_get_book (fixture->acct);
     auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
-#ifdef USE_CLANG_FUNC_SIG
-#define _func "Account *xaccCloneAccount(const Account *, QofBook *)"
-#else
-#define _func "xaccCloneAccount"
-#endif
-    auto msg1 = _func ": assertion 'GNC_IS_ACCOUNT(from)' failed";
-    auto msg2 = _func ": assertion 'QOF_IS_BOOK(book)' failed";
-#undef _func
+    auto msg1 = ": assertion 'GNC_IS_ACCOUNT(from)' failed";
+    auto msg2 = ": assertion 'QOF_IS_BOOK(book)' failed";
     auto check = test_error_struct_new("gnc.engine", loglevel, msg1);
     AccountPrivate *acct_p, *clone_p;
     auto oldlogger = g_log_set_default_handler ((GLogFunc)test_null_handler,
                                                 check);
-    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler, check);
+    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_substring_handler, check);
     clone = xaccCloneAccount (NULL, book);
     g_assert (clone == NULL);
     g_assert_cmpint (check->hits, ==, 1);
@@ -1095,14 +1083,8 @@ test_gnc_account_insert_remove_split (Fixture *fixture, gconstpointer pData)
     Split *split3 = xaccMallocSplit (book);
     TestSignal sig1, sig2, sig3;
     AccountPrivate *priv = fixture->func->get_private (fixture->acct);
-#ifdef USE_CLANG_FUNC_SIG
-#define _func "gboolean gnc_account_insert_split(Account *, Split *)"
-#else
-#define _func "gnc_account_insert_split"
-#endif
-    auto msg1 = _func ": assertion 'GNC_IS_ACCOUNT(acc)' failed";
-    auto msg2 = _func ": assertion 'GNC_IS_SPLIT(s)' failed";
-#undef _func
+    auto msg1 = ": assertion 'GNC_IS_ACCOUNT(acc)' failed";
+    auto msg2 = ": assertion 'GNC_IS_SPLIT(s)' failed";
     auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
 //    auto log_domain = "gnc.engine";
     auto check1 = test_error_struct_new("gnc.engine", loglevel, msg1);
@@ -1116,7 +1098,7 @@ test_gnc_account_insert_remove_split (Fixture *fixture, gconstpointer pData)
     test_add_error (check2);
     logger = g_log_set_handler ("gnc.engine", loglevel,
                                 (GLogFunc)test_null_handler, check3);
-    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_list_handler, NULL);
+    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_list_substring_handler, NULL);
 
     /* Check that the call fails with invalid account and split (throws) */
     g_assert (!gnc_account_insert_split (NULL, split1));
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bced61f..190bd21 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -608,7 +608,7 @@ libgnucash/core-utils/gnc-locale-utils.c
 libgnucash/core-utils/gnc-path.c
 libgnucash/core-utils/gnc-prefs.c
 libgnucash/doc/doxygen_main_page.c
-libgnucash/engine/Account.c
+libgnucash/engine/Account.cpp
 libgnucash/engine/business-core.scm
 libgnucash/engine/cap-gains.c
 libgnucash/engine/cashobjects.c



Summary of changes:
 common/test-core/test-stuff.h                      |    7 +-
 common/test-core/unittest-support.c                |   44 +
 common/test-core/unittest-support.h                |   20 +
 gnucash/gnome-utils/gnc-file.c                     |    6 -
 libgnucash/app-utils/test/test-option-util.cpp     |   10 +-
 .../backend/dbi/test/test-backend-dbi-basic.cpp    |   14 +-
 libgnucash/backend/sql/gnc-slots-sql.cpp           |   71 +-
 libgnucash/backend/xml/io-gncxml-v1.cpp            |    2 +-
 libgnucash/backend/xml/sixtp-dom-generators.cpp    |    4 +-
 libgnucash/backend/xml/sixtp-dom-parsers.cpp       |    2 +-
 .../backend/xml/test/test-date-converting.cpp      |    2 +-
 .../backend/xml/test/test-dom-converters1.cpp      |    2 +-
 libgnucash/backend/xml/test/test-kvp-frames.cpp    |    6 +-
 .../backend/xml/test/test-load-example-account.cpp |    2 +-
 libgnucash/backend/xml/test/test-load-xml2.cpp     |    2 +-
 libgnucash/backend/xml/test/test-save-in-lang.cpp  |    2 +-
 .../backend/xml/test/test-string-converters.cpp    |    2 +-
 libgnucash/backend/xml/test/test-xml-account.cpp   |    2 +-
 libgnucash/backend/xml/test/test-xml-commodity.cpp |    2 +-
 libgnucash/backend/xml/test/test-xml-pricedb.cpp   |    2 +-
 .../backend/xml/test/test-xml-transaction.cpp      |    3 +-
 libgnucash/backend/xml/test/test-xml2-is-file.cpp  |    2 +-
 libgnucash/core-utils/gnc-glib-utils.h             |    8 +
 libgnucash/engine/{Account.c => Account.cpp}       | 1339 ++++++++------------
 libgnucash/engine/Account.h                        |   12 +-
 libgnucash/engine/AccountP.h                       |    7 +
 libgnucash/engine/CMakeLists.txt                   |    2 +-
 libgnucash/engine/Makefile.am                      |    2 +-
 libgnucash/engine/Scrub.c                          |   14 +-
 libgnucash/engine/Split.c                          |   72 +-
 libgnucash/engine/Split.h                          |    8 +
 libgnucash/engine/Transaction.c                    |  117 +-
 libgnucash/engine/Transaction.h                    |    8 +
 libgnucash/engine/gnc-aqbanking-templates.cpp      |   22 +-
 libgnucash/engine/gnc-budget.c                     |   42 +-
 libgnucash/engine/gnc-commodity.c                  |   12 +-
 libgnucash/engine/gnc-commodity.h                  |    8 +
 libgnucash/engine/gnc-engine.h                     |    7 +
 libgnucash/engine/gnc-features.c                   |   27 +
 libgnucash/engine/gnc-features.h                   |   13 +
 libgnucash/engine/gnc-lot.c                        |   26 +-
 libgnucash/engine/gnc-lot.h                        |    9 +
 libgnucash/engine/gnc-pricedb.h                    |    8 +
 libgnucash/engine/gncCustomer.c                    |   30 +-
 libgnucash/engine/gncEmployee.c                    |   37 +-
 libgnucash/engine/gncInvoice.c                     |    8 +-
 libgnucash/engine/gncJob.c                         |   12 +-
 libgnucash/engine/gncVendor.c                      |   30 +-
 libgnucash/engine/guid.cpp                         |   19 +-
 libgnucash/engine/guid.hpp                         |    1 +
 libgnucash/engine/kvp-frame.cpp                    |  241 ++--
 libgnucash/engine/kvp-frame.hpp                    |  127 +-
 libgnucash/engine/kvp-value.cpp                    |   45 +-
 libgnucash/engine/kvp-value.hpp                    |    1 +
 libgnucash/engine/policy.h                         |    8 +
 libgnucash/engine/qof-backend.hpp                  |    2 +-
 libgnucash/engine/qof-string-cache.cpp             |   17 +-
 libgnucash/engine/qof-string-cache.h               |   10 +-
 libgnucash/engine/qofbook.cpp                      |  171 +--
 libgnucash/engine/qofinstance-p.h                  |   54 +-
 libgnucash/engine/qofinstance.cpp                  |  142 ++-
 libgnucash/engine/qofsession.cpp                   |    2 +-
 libgnucash/engine/test-core/test-engine-stuff.cpp  |    4 +-
 libgnucash/engine/test/gtest-import-map.cpp        |  151 +--
 libgnucash/engine/test/test-account-object.cpp     |    4 +-
 libgnucash/engine/test/test-kvp-frame.cpp          |   92 +-
 libgnucash/engine/test/utest-Account.cpp           |   36 +-
 libgnucash/engine/test/utest-Split.cpp             |   24 +-
 libgnucash/engine/test/utest-Transaction.cpp       |   36 +-
 po/POTFILES.in                                     |    2 +-
 70 files changed, 1611 insertions(+), 1667 deletions(-)
 rename libgnucash/engine/{Account.c => Account.cpp} (83%)



More information about the gnucash-changes mailing list