diff --git a/common/test-core/test-stuff.h b/common/test-core/test-stuff.h index 8fcd506537..6da2adb11d 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 #include - +#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/common/test-core/unittest-support.c b/common/test-core/unittest-support.c index 86cbe44ca1..dddcef8240 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) @@ -205,6 +228,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 61503dbe6c..f9e4849c0c 100644 --- a/common/test-core/unittest-support.h +++ b/common/test-core/unittest-support.h @@ -178,6 +178,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 @@ -213,6 +221,18 @@ gboolean test_null_handler (const char *log_domain, GLogLevelFlags log_level, void test_add_error (TestErrorStruct *error); 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 diff --git a/gnucash/gnome-utils/gnc-file.c b/gnucash/gnome-utils/gnc-file.c index 12d5e59764..aa88b2865a 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/app-utils/test/test-option-util.cpp b/libgnucash/app-utils/test/test-option-util.cpp index fd560fe55a..4c7d358b44 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(), == , "t"); - g_assert_cmpstr (slots->get_slot("options/Accounts/Use Split Action Field for Number")->get(), == , "t"); - g_assert_cmpstr (slots->get_slot("options/Business/Company Name")->get(), ==, "Bogus Company"); - g_assert_cmpfloat (slots->get_slot("options/Accounts/Day Threshold for Read-Only Transactions (red line)")->get(), ==, 17); + g_assert_cmpstr (slots->get_slot({"options", "Accounts", "Use Trading Accounts"})->get(), == , "t"); + g_assert_cmpstr (slots->get_slot({"options", "Accounts", "Use Split Action Field for Number"})->get(), == , "t"); + g_assert_cmpstr (slots->get_slot({"options", "Business", "Company Name"})->get(), ==, "Bogus Company"); + g_assert_cmpfloat (slots->get_slot({"options", "Accounts", "Day Threshold for Read-Only Transactions (red line)"})->get(), ==, 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 245ca9553c..8c0d75eb84 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 (guid_copy ( + frame->set ({"guid-val"}, new KvpValue (const_cast (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 8b35b27ef5..c8b36ff3a2 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; } } @@ -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 (); 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 (); cursor; cursor = cursor->next) { auto val = static_cast (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/io-gncxml-v1.cpp b/libgnucash/backend/xml/io-gncxml-v1.cpp index df50648e58..53d6039ea4 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-generators.cpp b/libgnucash/backend/xml/sixtp-dom-generators.cpp index 22a3f7e688..25504dd55a 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 (); if (!frame) break; - frame->for_each_slot (add_kvp_slot, static_cast (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 (ret)); + frame->for_each_slot_temp (&add_kvp_slot, ret); return ret; } diff --git a/libgnucash/backend/xml/sixtp-dom-parsers.cpp b/libgnucash/backend/xml/sixtp-dom-parsers.cpp index af4b197f97..fa0dca10e4 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-date-converting.cpp b/libgnucash/backend/xml/test/test-date-converting.cpp index 992ee85b21..cae7c194e7 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 -#include "test-stuff.h" #include "test-engine-stuff.h" #include @@ -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 d5499d96dd..1035c6e7be 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 -#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-kvp-frames.cpp b/libgnucash/backend/xml/test/test-kvp-frames.cpp index b9736ce4e2..508d60020c 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/backend/xml/test/test-load-example-account.cpp b/libgnucash/backend/xml/test/test-load-example-account.cpp index 576ddd1a45..8193ba348c 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 7731f8835a..f417fd6c2b 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 #include -#include #include #include } @@ -53,6 +52,7 @@ extern "C" #include "../gnc-backend-xml.h" #include "../io-gncxml-v2.h" #include "test-file-stuff.h" +#include #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 f7c0fb704e..670534831f 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 #include -#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 a8ad66af91..72f74ba212 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 #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 8a1eb87cc4..5022a9143c 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 #include -#include #include #include @@ -45,6 +44,7 @@ extern "C" #include "../sixtp-parsers.h" #include "../sixtp-dom-parsers.h" #include "test-file-stuff.h" +#include static QofBook* sixbook; diff --git a/libgnucash/backend/xml/test/test-xml-commodity.cpp b/libgnucash/backend/xml/test/test-xml-commodity.cpp index 07f8f43376..71a3060524 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 4ab584d9a3..18d22ef6b8 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 5828b43156..1154b3b830 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 #include -#include #include #include @@ -53,7 +52,7 @@ extern "C" #include "../sixtp-dom-parsers.h" #include "../io-gncxml-gen.h" #include "test-file-stuff.h" - +#include 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 f4234e6cfb..8b698f45e1 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 #include -#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/core-utils/gnc-glib-utils.h b/libgnucash/core-utils/gnc-glib-utils.h index 2999894f5d..a381825a93 100644 --- a/libgnucash/core-utils/gnc-glib-utils.h +++ b/libgnucash/core-utils/gnc-glib-utils.h @@ -39,6 +39,10 @@ #include +#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 83% rename from libgnucash/engine/Account.c rename to libgnucash/engine/Account.cpp index bcf5d0a952..a4d4995dbc 100644 --- a/libgnucash/engine/Account.c +++ b/libgnucash/engine/Account.cpp @@ -41,6 +41,9 @@ #include "gnc-pricedb.h" #include "qofinstance-p.h" #include "gnc-features.h" +#include "guid.hpp" + +#include static QofLogModule log_module = GNC_MOD_ACCOUNT; @@ -55,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>; +using ProbabilityVec=std::vector>; +using FlatKvpEntry=std::pair; + enum { LAST_SIGNAL @@ -171,7 +178,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(node->data); else { gchar *tmp_list = NULL; @@ -251,9 +258,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(qof_string_cache_insert("")); + priv->accountCode = static_cast(qof_string_cache_insert("")); + priv->description = static_cast(qof_string_cache_insert("")); priv->type = ACCT_TYPE_NONE; @@ -403,34 +410,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); @@ -446,10 +446,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)); @@ -473,10 +470,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(g_value_get_int(value))); break; case PROP_COMMODITY: - xaccAccountSetCommodity(account, g_value_get_object(value)); + xaccAccountSetCommodity(account, static_cast(g_value_get_object(value))); break; case PROP_COMMODITY_SCU: xaccAccountSetCommoditySCU(account, g_value_get_int(value)); @@ -491,19 +488,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(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(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(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(g_value_get_pointer(value))); break; case PROP_MARK: xaccAccountSetMark(account, g_value_get_int(value)); @@ -537,32 +534,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); @@ -595,7 +585,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -606,7 +596,7 @@ gnc_account_class_init (AccountClass *klass) "all its parent account names to indicate " "a unique account.", NULL, - G_PARAM_READABLE)); + static_cast(G_PARAM_READABLE))); g_object_class_install_property (gobject_class, @@ -618,7 +608,7 @@ gnc_account_class_init (AccountClass *klass) "be reporting code that is a synonym for " "the accountName.", NULL, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -630,7 +620,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -641,7 +631,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -652,7 +642,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -665,7 +655,7 @@ gnc_account_class_init (AccountClass *klass) ACCT_TYPE_NONE, NUM_ACCOUNT_TYPES - 1, ACCT_TYPE_BANK, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -676,7 +666,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -691,7 +681,7 @@ gnc_account_class_init (AccountClass *klass) 0, G_MAXINT32, 1000000, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -704,7 +694,7 @@ gnc_account_class_init (AccountClass *klass) "mismatched values in older versions of " "GnuCash.", FALSE, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -719,7 +709,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -733,7 +723,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -749,7 +739,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -766,7 +756,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -783,7 +773,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -818,7 +808,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(G_PARAM_READABLE))); g_object_class_install_property (gobject_class, @@ -826,7 +816,7 @@ gnc_account_class_init (AccountClass *klass) g_param_spec_pointer ("policy", "Policy", "The account lots policy.", - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -837,7 +827,7 @@ gnc_account_class_init (AccountClass *klass) 0, G_MAXINT16, 0, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -847,7 +837,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -859,7 +849,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -868,7 +858,7 @@ gnc_account_class_init (AccountClass *klass) "Tax Source", "This specifies where exported name comes from.", NULL, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -880,7 +870,7 @@ gnc_account_class_init (AccountClass *klass) (gint64)1, G_MAXINT64, (gint64)1, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -890,7 +880,7 @@ gnc_account_class_init (AccountClass *klass) "Whether the account should be hidden in the " "account tree.", FALSE, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -900,7 +890,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -910,7 +900,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -920,7 +910,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -929,7 +919,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(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -940,7 +930,7 @@ gnc_account_class_init (AccountClass *klass) (gint64)1, G_MAXINT64, (gint64)1, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -950,7 +940,7 @@ gnc_account_class_init (AccountClass *klass) "The online account which corresponds to this " "account for OFX import", NULL, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property( gobject_class, @@ -959,7 +949,7 @@ gnc_account_class_init (AccountClass *klass) "Associated income account", "Used by the OFX importer.", GNC_TYPE_GUID, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -969,7 +959,7 @@ gnc_account_class_init (AccountClass *klass) "The AqBanking account which corresponds to this " "account for AQBanking import", NULL, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, PROP_AB_BANK_CODE, @@ -978,7 +968,7 @@ gnc_account_class_init (AccountClass *klass) "The online account which corresponds to this " "account for AQBanking import", NULL, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -989,7 +979,7 @@ gnc_account_class_init (AccountClass *klass) (gint64)1, G_MAXINT64, (gint64)1, - G_PARAM_READWRITE)); + static_cast(G_PARAM_READWRITE))); g_object_class_install_property (gobject_class, @@ -999,7 +989,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(G_PARAM_READWRITE))); } @@ -1028,7 +1018,7 @@ static Account * gnc_coll_get_root_account (QofCollection *col) { if (!col) return NULL; - return qof_collection_get_data (col); + return static_cast(qof_collection_get_data (col)); } static void @@ -1101,7 +1091,7 @@ xaccMallocAccount (QofBook *book) g_return_val_if_fail (book, NULL); - acc = g_object_new (GNC_TYPE_ACCOUNT, NULL); + acc = static_cast(g_object_new (GNC_TYPE_ACCOUNT, NULL)); xaccInitAccount (acc, book); qof_event_gen (&acc->inst, QOF_EVENT_CREATE, NULL); @@ -1118,7 +1108,7 @@ gnc_account_create_root (QofBook *book) rpriv = GET_PRIVATE(root); xaccAccountBeginEdit(root); rpriv->type = ACCT_TYPE_ROOT; - CACHE_REPLACE(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); @@ -1135,7 +1125,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(g_object_new (GNC_TYPE_ACCOUNT, NULL)); g_return_val_if_fail (ret, NULL); from_priv = GET_PRIVATE(from); @@ -1147,9 +1137,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(qof_string_cache_insert(from_priv->accountName)); + priv->accountCode = static_cast(qof_string_cache_insert(from_priv->accountCode)); + priv->description = static_cast(qof_string_cache_insert(from_priv->description)); qof_instance_copy_kvp (QOF_INSTANCE (ret), QOF_INSTANCE (from)); @@ -1229,7 +1219,7 @@ xaccFreeAccount (Account *acc) for (lp = priv->lots; lp; lp = lp->next) { - GNCLot *lot = lp->data; + GNCLot *lot = static_cast(lp->data); gnc_lot_destroy (lot); } g_list_free (priv->lots); @@ -1261,15 +1251,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 +1318,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(acc)))) xaccSplitDestroy(split); } @@ -1365,7 +1356,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(lp->data); xaccSplitDestroy (s); } g_list_free(slist); @@ -1392,7 +1383,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(lp->data); gnc_lot_destroy (lot); } } @@ -1455,7 +1446,7 @@ xaccAcctChildrenEqual(const GList *na, while (na) { - Account *aa = na->data; + Account *aa = static_cast(na->data); Account *ab; GList *node = g_list_find_custom ((GList*)nb, aa, (GCompareFunc)compare_account_by_name); @@ -1465,7 +1456,7 @@ xaccAcctChildrenEqual(const GList *na, PINFO ("Unable to find matching child account."); return FALSE; } - ab = node->data; + ab = static_cast(node->data); if (!xaccAccountEqual(aa, ab, check_guids)) { char sa[GUID_ENCODING_LENGTH + 1]; @@ -1883,7 +1874,7 @@ xaccClearMarkDown (Account *acc, short val) priv->mark = val; for (node = priv->children; node; node = node->next) { - xaccClearMarkDown(node->data, val); + xaccClearMarkDown(static_cast(node->data), val); } } @@ -2254,7 +2245,7 @@ xaccAccountSetName (Account *acc, const char *str) return; xaccAccountBeginEdit(acc); - CACHE_REPLACE(priv->accountName, str); + priv->accountName = qof_string_cache_replace(priv->accountName, str); mark_account (acc); xaccAccountCommitEdit(acc); } @@ -2273,7 +2264,7 @@ xaccAccountSetCode (Account *acc, const char *str) return; xaccAccountBeginEdit(acc); - CACHE_REPLACE(priv->accountCode, str ? str : ""); + priv->accountCode = qof_string_cache_replace(priv->accountCode, str ? str : ""); mark_account (acc); xaccAccountCommitEdit(acc); } @@ -2292,7 +2283,7 @@ xaccAccountSetDescription (Account *acc, const char *str) return; xaccAccountBeginEdit(acc); - CACHE_REPLACE(priv->description, str ? str : ""); + priv->description = qof_string_cache_replace(priv->description, str ? str : ""); mark_account (acc); xaccAccountCommitEdit(acc); } @@ -2306,20 +2297,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); @@ -2330,7 +2321,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; } @@ -2355,7 +2346,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 @@ -2503,7 +2494,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); @@ -2691,7 +2682,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(g_list_nth_data(GET_PRIVATE(parent)->children, num)); } gint @@ -2706,7 +2697,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(node->data)) + 1; } return count; } @@ -2745,7 +2736,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(node->data)); depth = MAX(depth, child_depth); } return depth + 1; @@ -2768,7 +2759,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(child->data))); } return descendants; } @@ -2793,7 +2784,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(child->data))); } g_list_free(children); return descendants; @@ -2813,7 +2804,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(node->data); cpriv = GET_PRIVATE(child); if (g_strcmp0(cpriv->accountName, name) == 0) return child; @@ -2823,7 +2814,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(node->data); result = gnc_account_lookup_by_name (child, name); if (result) return result; @@ -2846,7 +2837,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(node->data); cpriv = GET_PRIVATE(child); if (g_strcmp0(cpriv->accountCode, code) == 0) return child; @@ -2856,7 +2847,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(node->data); result = gnc_account_lookup_by_code (child, code); if (result) return result; @@ -2884,7 +2875,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(node->data); priv = GET_PRIVATE(account); if (g_strcmp0(priv->accountName, names[0]) == 0) @@ -2950,7 +2941,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(node->data), user_data); } } @@ -2969,7 +2960,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(node->data); thunk(child, user_data); gnc_account_foreach_descendant(child, thunk, user_data); } @@ -2991,7 +2982,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(node->data); result = thunk(child, user_data); if (result) return(result); @@ -3067,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. */ - names = g_malloc(level * sizeof(gchar *)); + names = (gchar **)g_malloc(level * sizeof(gchar *)); names[--level] = NULL; for (a = account; level > 0; a = priv->parent) { @@ -3140,7 +3131,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; @@ -3267,7 +3258,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(node->data); if (!seen_a_transaction) { @@ -3383,7 +3374,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(node->data); if (xaccTransGetDate (xaccSplitGetParent (split)) <= today) return xaccSplitGetBalance (split); @@ -3517,7 +3508,7 @@ typedef struct static void xaccAccountBalanceHelper (Account *acc, gpointer data) { - CurrencyBalance *cb = data; + CurrencyBalance *cb = static_cast(data); gnc_numeric balance; if (!cb->fn || !cb->currency) @@ -3531,7 +3522,7 @@ xaccAccountBalanceHelper (Account *acc, gpointer data) static void xaccAccountBalanceAsOfDateHelper (Account *acc, gpointer data) { - CurrencyBalance *cb = data; + CurrencyBalance *cb = static_cast(data); gnc_numeric balance; g_return_if_fail (cb->asOfDateFn && cb->currency); @@ -3768,7 +3759,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(lot_list->data); /* If this lot is closed, then ignore it */ if (gnc_lot_is_closed (lot)) @@ -3807,7 +3798,7 @@ xaccAccountForEachLot(const Account *acc, } static void -set_boolean_key (Account *acc, const char* key, gboolean option) +set_boolean_key (Account *acc, std::vector const & path, gboolean option) { GValue v = G_VALUE_INIT; g_return_if_fail(GNC_IS_ACCOUNT(acc)); @@ -3815,17 +3806,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 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)) @@ -3842,13 +3833,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 * @@ -3856,7 +3847,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; } @@ -3869,7 +3860,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); } @@ -3879,8 +3870,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; } @@ -3893,7 +3883,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); } @@ -3904,7 +3894,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); @@ -3921,11 +3911,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); @@ -3937,13 +3927,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 @@ -3973,13 +3963,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 @@ -4111,7 +4101,7 @@ xaccAccountStringToEnum(const char* str) /********************************************************************\ \********************************************************************/ -static char * +static char const * account_type_name[NUM_ACCOUNT_TYPES] = { N_("Bank"), @@ -4310,7 +4300,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); @@ -4335,7 +4325,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); } @@ -4352,10 +4342,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)) @@ -4385,10 +4375,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); } @@ -4402,8 +4392,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); @@ -4428,8 +4418,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); } @@ -4444,8 +4434,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; @@ -4471,8 +4461,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); } @@ -4487,7 +4477,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); } @@ -4502,7 +4492,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"}); } /********************************************************************\ @@ -4511,7 +4501,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); } /********************************************************************\ @@ -4522,7 +4512,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; } @@ -4538,7 +4528,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); } @@ -4592,13 +4582,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 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 */ @@ -4611,7 +4601,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); @@ -4620,7 +4610,6 @@ xaccAccountGainsAccount (Account *acc, gnc_commodity *curr) gains_account = xaccAccountLookup (guid, qof_instance_get_book(acc)); - g_free (curr_name); return gains_account; } @@ -4640,11 +4629,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); @@ -4662,7 +4650,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; } @@ -4678,7 +4666,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); } @@ -4692,7 +4680,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; } @@ -4712,8 +4700,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); } @@ -4730,8 +4718,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; } @@ -4763,7 +4751,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(slp->data); Transaction *ltrans = xaccSplitGetParent(lsplit); if (g_strcmp0 (description, xaccTransGetDescription (ltrans)) == 0) @@ -4821,7 +4809,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 (node->data)); g_list_free(children); LEAVE (" "); } @@ -4839,12 +4827,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 (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 (node_b->data); priv_b = GET_PRIVATE(acc_b); if (0 != null_strcmp(priv_a->accountName, priv_b->accountName)) @@ -4881,7 +4869,7 @@ gnc_account_merge_children (Account *parent) /* consolidate transactions */ while (priv_b->splits) - xaccSplitSetAccount (priv_b->splits->data, acc_a); + xaccSplitSetAccount (static_cast (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 +4894,7 @@ xaccSplitsBeginStagedTransactionTraversals (GList *splits) for (lp = splits; lp; lp = lp->next) { - Split *s = lp->data; + Split *s = static_cast (lp->data); Transaction *trans = s->parent; if (trans) @@ -4987,7 +4975,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_p->data); trans = s->parent; if (trans && (trans->marker < stage)) { @@ -5021,15 +5009,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 (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_p->data); trans = s->parent; if (trans && (trans->marker < stage)) { @@ -5105,17 +5093,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 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); } @@ -5127,19 +5112,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 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); } @@ -5150,28 +5131,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 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); @@ -5182,312 +5153,322 @@ 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) */ -struct account_probability +struct AccountProbability { double product; /* product of probabilities */ 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 +struct AccountTokenCount +{ + std::string account_guid; + int64_t 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 */ -#define PROBABILITY_FACTOR 100000 -static void -buildProbabilities(gpointer key, gpointer value, gpointer data) +struct TokenAccountsInfo { - 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)); -} - -/** Frees an array of the same time that buildProperties built */ -static void -freeProbabilities(gpointer key, gpointer value, gpointer data) -{ - /* free up the struct account_probability that was allocated - * in gnc_account_find_account_bayes() - */ - g_free(value); -} + std::vector 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 { - 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, TokenAccountsInfo & 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 = key; - } + tokenInfo.total_count += value->get(); + 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); + this_account.token_count = value->get(); + 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 */ +static constexpr int probability_factor = 100000; -#define threshold (.90 * PROBABILITY_FACTOR) /* 90% */ +static FinalProbabilityVec +build_probabilities(ProbabilityVec const & first_pass) +{ + FinalProbabilityVec ret; + for (auto const & first_pass_prob : first_pass) + { + 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 AccountInfo +highest_probability(FinalProbabilityVec const & probabilities) +{ + AccountInfo ret {"", std::numeric_limits::min()}; + for (auto const & prob : probabilities) + if (prob.second > ret.probability) + ret = AccountInfo {prob.first, prob.second}; + return ret; +} + +static ProbabilityVec +get_first_pass_probabilities(GncImportMatchMap * imap, GList * tokens) +{ + 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) + { + TokenAccountsInfo tokenInfo{}; + auto path = std::string{IMAP_FRAME_BAYES "/"} + static_cast (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(), [¤t_account_token] + (std::pair 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 */ + AccountProbability new_probability; + new_probability.product = ((double)current_account_token.token_count / + (double)tokenInfo.total_count); + 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 */ + } + 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 (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 +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 (); + auto flat_kvp = imap_frame->flatten_kvp (); + auto root = gnc_account_get_root (acc); + std::vector 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 (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 */ Account* gnc_account_imap_find_account_bayes (GncImportMatchMap *imap, GList *tokens) { - 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) - { - PINFO("imap is null, returning null"); - LEAVE(" "); - return NULL; + return nullptr; + check_import_map_data (imap->book); + 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; } - - /* 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) - { - 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) - { - /* 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 = 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); - } - 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 / - (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); - } - } /* 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 */ - } - - /* 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); - - return account; - } - 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(&guid), imap->book); + return account; } - static void -change_imap_entry (GncImportMatchMap *imap, gchar *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); @@ -5503,15 +5484,10 @@ change_imap_entry (GncImportMatchMap *imap, gchar *kvp_path, int64_t token_count 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); - - /* 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); + qof_instance_set_path_kvp (QOF_INSTANCE (imap->acc), &value, {path}); + gnc_features_set_used (imap->book, GNC_FEATURE_GUID_FLAT_BAYESIAN); } - /** Updates the imap for a given account using a list of tokens */ void gnc_account_imap_add_account_bayes (GncImportMatchMap *imap, @@ -5520,7 +5496,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(" "); @@ -5529,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); @@ -5548,181 +5525,107 @@ 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); - - kvp_path = g_strdup_printf (IMAP_FRAME_BAYES "/%s/%s", - (char*)current_token->data, - guid_string); - + auto path = std::string {IMAP_FRAME_BAYES} + '/' + static_cast(current_token->data) + '/' + 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, 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(" "); } /*******************************************************************************/ 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; - - struct imap_info *imapInfo_node; - - struct imap_info *imapInfo = (struct imap_info*)user_data; - + gchar *guid_string = NULL; + auto imapInfo = (GncImapInfo*)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); + PINFO("build_non_bayes: 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 = g_malloc(sizeof(*imapInfo_node)); + auto imapInfo_node = static_cast (g_malloc(sizeof(GncImapInfo))); 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 std::tuple +parse_bayes_imap_info (std::string const & imap_bayes_entry) +{ + 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 std::tuple {header, keyword, account_guid}; } static void -build_bayes (const char *key, const GValue *value, gpointer user_data) +build_bayes (const char *key, KvpValue * value, GncImapInfo & 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) + auto slots = qof_instance_get_slots_prefix (QOF_INSTANCE (imapInfo.source_account), IMAP_FRAME_BAYES); + if (!slots.size()) return; + for (auto const & entry : slots) { - 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); - } + 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 (g_malloc (sizeof (GncImapInfo))); + auto count = entry.second->get (); + 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); + }; } - -static void -build_non_bayes (const char *key, const GValue *value, gpointer user_data) -{ - 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 = 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); - - g_free (kvp_path); - g_free (guid_string); - } -} - - 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); - + 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}; + qof_instance_foreach_slot_prefix (QOF_INSTANCE (acc), IMAP_FRAME_BAYES, &build_bayes, imapInfo); return imapInfo.list; } - GList * gnc_account_imap_get_info (Account *acc, const char *category) { @@ -5753,12 +5656,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 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; @@ -5766,7 +5667,6 @@ gnc_account_get_map_entry (Account *acc, const char *full_category) text = g_strdup (string); } } - g_free (kvp_path); return text; } @@ -5775,18 +5675,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); + 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); } @@ -5794,208 +5690,6 @@ gnc_account_delete_map_entry (Account *acc, char *full_category, gboolean empty) g_free (full_category); } -/*******************************************************************************/ - -static gchar * -look_for_old_separator_descendants (Account *root, gchar *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, separator); - - /* Go through list of top level accounts */ - for (ptr = top_accounts; ptr; ptr = g_list_next (ptr)) - { - const gchar *name = xaccAccountGetName (ptr->data); - - // we are looking for the longest top level account that matches - if (g_str_has_prefix (full_name, 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 - - 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); - - if (G_VALUE_HOLDS_INT64 (&value)) - token_count = g_value_get_int64 (&value); - - // 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); -} - - -static Account * -look_for_old_mapping (GncImapInfo *imapInfo) -{ - 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) - { - full_name = look_for_old_separator_descendants (root, full_name, sep); - map_account = gnc_account_lookup_by_full_name (root, full_name); // lets try again - } - - PINFO("Full account name is '%s'", full_name); - - g_free (full_name); - - return map_account; -} - -static void -convert_imap_account (Account *acc) -{ - GList *imap_list, *node; - gchar *acc_name = NULL; - - acc_name = gnc_account_get_full_name (acc); - PINFO("Source Acc '%s'", acc_name); - - imap_list = gnc_account_imap_get_info_bayes (acc); - - if (g_list_length (imap_list) > 0) // we have mappings - { - 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 = 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); - } - g_free (acc_name); - g_list_free (imap_list); // Free the List -} - -void -gnc_account_imap_convert_bayes (QofBook *book) -{ - 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; - - if (run_once == FALSE) - { - 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 = ptr->data; - - convert_imap_account (acc); - } - g_list_free (accts); - - g_value_init (&value_b, G_TYPE_BOOLEAN); - - g_value_set_boolean (&value_b, TRUE); - - // set the run-once value - qof_instance_set_kvp (QOF_INSTANCE (book), "changed-bayesian-to-guid", &value_b); - } -} - - /* ================================================================ */ /* QofObject function implementation and registration */ @@ -6003,7 +5697,6 @@ static void gnc_account_book_end(QofBook* book) { Account *root_account = gnc_book_get_root_account(book); - xaccAccountBeginEdit(root_account); xaccAccountDestroy(root_account); } @@ -6020,7 +5713,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 13f265c888..477d406af3 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) ( @@ -1446,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); - /** @} */ @@ -1517,6 +1515,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 a3a2bdd642..a1ab6a0747 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 eeeb7f9428..993eb5e624 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 49c70ccea6..088b9b4f8e 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/Scrub.c b/libgnucash/engine/Scrub.c index d27752ebed..f168a248ee 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 +#include "qofinstance-p.h" #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "gnc.engine.scrub" @@ -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_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_kvp (QOF_INSTANCE (account), "notes", &v); + 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_kvp (QOF_INSTANCE (account), "placeholder", &v); + 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 c7e86d82da..6e18d15b13 100644 --- a/libgnucash/engine/Split.c +++ b/libgnucash/engine/Split.c @@ -182,40 +182,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_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_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_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_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_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_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_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_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_kvp (QOF_INSTANCE (split), value, 1, "gains-source"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -268,40 +259,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_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_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_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_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_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_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_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_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_kvp (QOF_INSTANCE (split), value, 1, "gains-source"); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -1095,7 +1077,7 @@ xaccSplitDetermineGainStatus (Split *split) return; } - qof_instance_get_kvp (QOF_INSTANCE (split), "gains-source", &v); + 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) @@ -1987,7 +1969,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_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"; @@ -2004,7 +1986,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_kvp (QOF_INSTANCE (s), &v, 1, "split-type"); SET_GAINS_VDIRTY(s); mark_split(s); qof_instance_set_dirty(QOF_INSTANCE(s)); @@ -2141,7 +2123,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_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(); @@ -2153,7 +2135,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_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(); @@ -2168,10 +2150,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_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_kvp (QOF_INSTANCE (split), &v, 1, void_former_val_str); /* Marking dirty handled by SetAmount etc. */ xaccSplitSetAmount (split, zero); @@ -2185,8 +2167,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_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/Split.h b/libgnucash/engine/Split.h index 1c450809e7..4d7f41706c 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.c b/libgnucash/engine/Transaction.c index 811100d1a0..5fc7c7eeb1 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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)); @@ -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_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_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/Transaction.h b/libgnucash/engine/Transaction.h index a196e89553..2d143898e4 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-aqbanking-templates.cpp b/libgnucash/engine/gnc-aqbanking-templates.cpp index eb8d6e7390..ad6b8fda0a 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" @@ -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(node->data)->get(); 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());}; 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();}; - 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/gnc-budget.c b/libgnucash/engine/gnc-budget.c index c49af4ef0b..a4a2a21a15 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 + 1]; + 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_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 + 1]; + 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_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_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 + 1]; + 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_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 + 1]; + 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_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 f218f8f6fc..c9c28ed123 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_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_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_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_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_kvp (QOF_INSTANCE(cm), &v, 1, "user_symbol"); } else - qof_instance_set_kvp (QOF_INSTANCE(cm), "user_symbol", NULL); + 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-commodity.h b/libgnucash/engine/gnc-commodity.h index 8daa83b375..b5dcc93120 100644 --- a/libgnucash/engine/gnc-commodity.h +++ b/libgnucash/engine/gnc-commodity.h @@ -53,6 +53,10 @@ typedef struct _GncCommodityNamespaceClass gnc_commodity_namespaceClass; #include #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 f8f1c986ef..651cf44e52 100644 --- a/libgnucash/engine/gnc-engine.h +++ b/libgnucash/engine/gnc-engine.h @@ -39,6 +39,10 @@ #include #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.c b/libgnucash/engine/gnc-features.c index f125602b06..4d38fa7b1c 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 (requires at least Gnucash 2.6.19)" }, { 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 39f1c03233..2beca420ed 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 @{ */ @@ -46,6 +50,7 @@ #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" /** @} */ @@ -64,6 +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 /*__cplusplus*/ #endif /* GNC_FEATURES_H */ /** @} */ /** @} */ diff --git a/libgnucash/engine/gnc-lot.c b/libgnucash/engine/gnc-lot.c index 77b3becadc..7df4483dbb 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_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_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_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_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_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_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_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_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_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_kvp (QOF_INSTANCE (lot), &v, 1, "notes"); qof_instance_set_dirty(QOF_INSTANCE(lot)); gnc_lot_commit_edit(lot); } diff --git a/libgnucash/engine/gnc-lot.h b/libgnucash/engine/gnc-lot.h index 64e1dfaa0c..c725b6f8f7 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 f7eefa3e1e..671c87ea2e 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/gncCustomer.c b/libgnucash/engine/gncCustomer.c index 9b4ed8073f..48b470f382 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_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_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_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_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_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_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 ebfb5185cc..d992b0ac8b 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_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_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_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_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_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_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 651865bb51..ac8eaacceb 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_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_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_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_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 bd4c6720dd..2ee97b796e 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_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_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_kvp (QOF_INSTANCE (job), &v, 1, GNC_JOB_RATE); } else { - qof_instance_set_kvp (QOF_INSTANCE (job), GNC_JOB_RATE, NULL); + qof_instance_set_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_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 3ebdb2bb3e..b5f418cc60 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_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_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_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_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_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_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/guid.cpp b/libgnucash/engine/guid.cpp index e939ac8ad6..11aaebf11d 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 (); } @@ -356,6 +358,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 db6e4dccc0..837d509920 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 f1368bc2dc..3d09e2fe56 100644 --- a/libgnucash/engine/kvp-frame.cpp +++ b/libgnucash/engine/kvp-frame.cpp @@ -38,6 +38,7 @@ extern "C" #include #include #include +#include /* This static indicates the debugging module that this .o belongs to. */ static QofLogModule log_module = "qof.kvp"; @@ -67,137 +68,119 @@ 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 (); + Path send; + std::copy (path.begin () + 1, path.end (), std::back_inserter (send)); + return child->get_child_frame_or_nullptr (send); } -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()) - { - qof_string_cache_remove(spot->first); - ret = spot->second; - m_valuemap.erase(spot); - } + 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 (); + 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); + ret = spot->second; + m_valuemap.erase (spot); + } if (value) { - auto cachedkey = - static_cast(qof_string_cache_insert(key)); - m_valuemap.insert({cachedkey,value}); + auto cachedkey = static_cast (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(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(); - } - return cur_frame; -} - -KvpValue* -KvpFrameImpl::set(Path path, KvpValue* value) noexcept -{ - auto last_key = path.back(); - path.pop_back(); - auto cur_frame = walk_path_or_nullptr(this, path); - if (cur_frame == nullptr) + auto key = path.back (); + path.pop_back (); + auto target = get_child_frame_or_nullptr (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::set_path (Path path, KvpValue* value) 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(); - } - 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(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_create (path); + if (!target) + return nullptr; + return target->set_impl (key, value); +} + +KvpValue * +KvpFrameImpl::get_slot (Path path) noexcept +{ + auto key = path.back(); + path.pop_back(); + 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 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(); } @@ -214,46 +197,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 -{ - 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; @@ -479,4 +422,30 @@ gnc_value_list_get_type (void) return type; } -/* ========================== END OF FILE ======================= */ +void +KvpFrame::flatten_kvp_impl(std::vector path, std::vector & entries) const noexcept +{ + for (auto const & entry : m_valuemap) + { + std::vector new_path {path}; + new_path.push_back("/"); + if (entry.second->get_type() == KvpValue::Type::FRAME) + { + new_path.push_back(entry.first); + entry.second->get()->flatten_kvp_impl(new_path, entries); + } + else + { + new_path.emplace_back (entry.first); + entries.emplace_back (new_path, entry.second); + } + } +} + +std::vector +KvpFrame::flatten_kvp(void) const noexcept +{ + std::vector ret; + flatten_kvp_impl({}, ret); + return ret; +} diff --git a/libgnucash/engine/kvp-frame.hpp b/libgnucash/engine/kvp-frame.hpp index 52908cd586..23eb0c6153 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. @@ -93,7 +89,10 @@ #include #include #include +#include +#include using Path = std::vector; +using KvpEntry = std::pair , KvpValue*>; /** Implements KvpFrame. * It's a struct because QofInstance needs to use the typename to declare a @@ -143,7 +142,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 @@ -158,18 +157,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 @@ -187,6 +174,12 @@ struct KvpFrameImpl * @return A std::string representing the frame and all its children. */ 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 &) const noexcept; /** * Report the keys in the immediate frame. Be sensible about using this, it * isn't a very efficient way to iterate. @@ -194,21 +187,38 @@ struct KvpFrameImpl */ std::vector 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; - /** Convenience wrapper for std::for_each, which should be preferred. + KvpValue* get_slot(Path keys) noexcept; + + /** The function should be of the form: + * func (char const *, KvpValue *, data_type &); + * Do not pass nullptr as the function. */ - void for_each_slot(void (*proc)(const char *key, KvpValue *value, - void * data), - void *data) const noexcept; + template + void for_each_slot_temp(func_type const &, data_type &) const noexcept; + + template + 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 + void for_each_slot_prefix(std::string const & prefix, func_type const &, data_type &) const noexcept; + + template + 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 + flatten_kvp(void) const noexcept; /** Test for emptiness * @return true if the frame contains nothing. @@ -218,8 +228,69 @@ struct KvpFrameImpl private: map_type m_valuemap; + + 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::vector &) const noexcept; + KvpValue * set_impl (std::string const &, KvpValue *) noexcept; }; +template +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 +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 +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 +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/kvp-value.cpp b/libgnucash/engine/kvp-value.cpp index 55e0e6e08f..990197e41e 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 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(val->data); output << ' ' << realvalue->to_string() << ','; } - output << " ]"; output << ")"; } @@ -161,53 +159,66 @@ struct to_string_visitor : boost::static_visitor { 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 << " (gnc_numeric)"; } 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()->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 003ee7d702..78a8eb7fa7 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 T get() const noexcept; diff --git a/libgnucash/engine/policy.h b/libgnucash/engine/policy.h index 42dc812ce7..71e4c0ed8e 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-backend.hpp b/libgnucash/engine/qof-backend.hpp index 871fec8ceb..ce0df972d7 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 } +#include "qofinstance-p.h" #include #include #include diff --git a/libgnucash/engine/qof-string-cache.cpp b/libgnucash/engine/qof-string-cache.cpp index 70e79d7e6d..caba239fbb 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 (cache_key); } else { @@ -126,10 +126,17 @@ qof_string_cache_insert(gconstpointer key) guint* refcount = static_cast(g_malloc(sizeof(guint))); *refcount = 1; g_hash_table_insert(cache, new_key, refcount); - return new_key; + return static_cast (new_key); } } return NULL; } +char * +qof_string_cache_replace(char const * dst, char const * src) +{ + 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 4aaa485a6d..f45ff1b19e 100644 --- a/libgnucash/engine/qof-string-cache.h +++ b/libgnucash/engine/qof-string-cache.h @@ -79,14 +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); -#define CACHE_INSERT(str) qof_string_cache_insert((gconstpointer)(str)) +/** Same as CACHE_REPLACE below, but safe to call from C++. + */ +char * qof_string_cache_replace(const char * dst, const char * src); + +#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 2bcbebc5fe..918e516298 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("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(AB_KEY "/" AB_TEMPLATES); - qof_instance_get_kvp (QOF_INSTANCE (book), key, value); - break; + key = const_cast(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("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(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; @@ -608,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; } @@ -1085,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(); @@ -1097,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); } @@ -1118,10 +1073,10 @@ 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()); - g_hash_table_insert (*(GHashTable**)user_data, (gchar*)key, descr); + g_hash_table_insert (user_data, (gchar*)key, descr); } GHashTable * @@ -1131,11 +1086,11 @@ 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(); - frame->for_each_slot(&add_feature_to_hash, &features); + frame = slot->get(); + frame->for_each_slot_temp(&add_feature_to_hash, features); } return features; } @@ -1145,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(); - feature = feature_frame->get_slot(key); + feature = feature_frame->get_slot({key}); } if (feature == nullptr || g_strcmp0 (feature->get(), descr)) { @@ -1223,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 0c0d4fd1bb..102af1ed70 100644 --- a/libgnucash/engine/qofinstance-p.h +++ b/libgnucash/engine/qofinstance-p.h @@ -25,6 +25,7 @@ * * Copyright (C) 2003 Linas Vepstas * Copyright (c) 2007 David Hampton + * Copyright 2017 Aaron Laws */ #ifndef QOF_INSTANCE_P_H @@ -33,6 +34,8 @@ #include "qofinstance.h" #ifdef __cplusplus +#include "kvp-frame.hpp" +#include extern "C" { #endif @@ -113,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_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_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. @@ -149,15 +153,39 @@ 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_delete (const QofInstance *inst, const char *path); -void qof_instance_slot_delete_if_empty (const QofInstance *inst, - const char *path); +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); #ifdef __cplusplus +} /* extern "C" */ + +void qof_instance_get_path_kvp (QofInstance *, GValue *, std::vector const &); + +void qof_instance_set_path_kvp (QofInstance *, GValue const *, std::vector const &); + +bool qof_instance_has_path_slot (QofInstance const *, std::vector const &); + +void qof_instance_slot_path_delete (QofInstance const *, std::vector const &); + +void qof_instance_slot_path_delete_if_empty (QofInstance const *, std::vector const &); + +/** Returns all keys that match the given prefix and their corresponding values.*/ +std::vector > +qof_instance_get_slots_prefix (QofInstance const *, std::string const & prefix); + +/** + * 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 +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/qofinstance.cpp b/libgnucash/engine/qofinstance.cpp index c307aeed7d..e82980c34a 100644 --- a/libgnucash/engine/qofinstance.cpp +++ b/libgnucash/engine/qofinstance.cpp @@ -26,6 +26,7 @@ * * Copyright (C) 2003 Linas Vepstas * Copyright (c) 2007 David Hampton + * Copyright 2017 Aaron Laws */ #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 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_kvp (QofInstance * inst, GValue const * value, unsigned count, ...) { - auto temp = gvalue_from_kvp_value (inst->kvp_data->get_slot(key)); + std::vector 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 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_kvp (QofInstance * inst, GValue * value, unsigned count, ...) +{ + std::vector 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); } } @@ -1113,18 +1144,18 @@ 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(guid))); - container->set("date", new KvpValue(time)); - delete inst->kvp_data->set_path(path, new KvpValue(container)); + container->set({key}, new KvpValue(const_cast(guid))); + container->set({"date"}, new KvpValue(time)); + 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 const & path, const GncGUID *guid) { if (v->get_type() != KvpValue::Type::FRAME) return FALSE; auto frame = v->get(); - 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(); @@ -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(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(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,29 +1278,62 @@ qof_instance_kvp_merge_guids (const QofInstance *target, } } +bool qof_instance_has_path_slot (QofInstance const * inst, std::vector 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; + return inst->kvp_data->get_slot({path}) != NULL; +} + +void qof_instance_slot_path_delete (QofInstance const * inst, std::vector const & path) +{ + delete inst->kvp_data->set (path, nullptr); } void -qof_instance_slot_delete (const QofInstance *inst, const char *path) +qof_instance_slot_delete (QofInstance const *inst, char const * path) { - inst->kvp_data->set(path, nullptr); + delete inst->kvp_data->set ({path}, nullptr); } -void -qof_instance_slot_delete_if_empty (const QofInstance *inst, const char *path) +void qof_instance_slot_path_delete_if_empty (QofInstance const * inst, std::vector const & path) { - auto slot = inst->kvp_data->get_slot(path); + auto slot = inst->kvp_data->get_slot (path); if (slot) { - auto frame = slot->get(); + auto frame = slot->get (); if (frame && frame->empty()) - inst->kvp_data->set(path, nullptr); + delete inst->kvp_data->set (path, nullptr); } } + +void +qof_instance_slot_delete_if_empty (QofInstance const *inst, char const * path) +{ + auto slot = inst->kvp_data->get_slot ({path}); + if (slot) + { + auto frame = slot->get (); + if (frame && frame->empty ()) + delete inst->kvp_data->set ({path}, nullptr); + } +} + +std::vector > +qof_instance_get_slots_prefix (QofInstance const * inst, std::string const & prefix) +{ + std::vector > 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 { @@ -1277,11 +1341,11 @@ struct wrap_param void *user_data; }; } + 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(data); if (val->get_type() != KvpValue::Type::FRAME) gv = gvalue_from_kvp_value(val); else @@ -1290,7 +1354,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); } @@ -1299,12 +1363,12 @@ 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(); 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 45729ea906..2049b5b767 100644 --- a/libgnucash/engine/qofsession.cpp +++ b/libgnucash/engine/qofsession.cpp @@ -50,12 +50,12 @@ extern "C" #include #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 b95c14de2a..ab2cb021fe 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 #include #include -#include #include "Account.h" #include "AccountP.h" @@ -71,6 +70,7 @@ extern "C" #include "test-stuff.h" #include "test-engine-strings.h" } +#include static gboolean glist_strings_only = FALSE; @@ -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 47746d6d4c..4f6c7cde7c 100644 --- a/libgnucash/engine/test/gtest-import-map.cpp +++ b/libgnucash/engine/test/gtest-import-map.cpp @@ -25,11 +25,12 @@ extern "C" #include #include "../Account.h" #include -#include } +#include #include #include +#include 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(xaccAccountGetGUID(t_expense_account1))); - auto acc2_val = new KvpValue(const_cast(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}, 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); @@ -289,103 +292,103 @@ 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"}); auto check_account = [this](KvpValue* v) { return (v->get(), 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}); EXPECT_EQ(1, value->get()); - value = root->get_slot({IMAP_FRAME_BAYES, bar, acct1_guid}); + value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + bar + "/" + acct1_guid}); EXPECT_EQ(1, value->get()); - value = root->get_slot({IMAP_FRAME_BAYES, baz, acct2_guid}); + value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + baz + "/" + acct2_guid}); EXPECT_EQ(1, value->get()); - value = root->get_slot({IMAP_FRAME_BAYES, waldo, acct2_guid}); + value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + waldo + "/" + acct2_guid}); EXPECT_EQ(1, value->get()); - value = root->get_slot({IMAP_FRAME_BAYES, pepper, acct1_guid}); + value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + pepper + "/" + acct1_guid}); EXPECT_EQ(1, value->get()); - value = root->get_slot({IMAP_FRAME_BAYES, salt, acct2_guid}); + value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + acct2_guid}); EXPECT_EQ(1, value->get()); - value = root->get_slot({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({IMAP_FRAME_BAYES, baz, acct2_guid}); + value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + baz + "/" + acct2_guid}); EXPECT_EQ(2, value->get()); } - -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 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(10)); auto val2 = new KvpValue(static_cast(5)); auto val3 = new KvpValue(static_cast(2)); - - // Test for existing entries, all will be 1 - auto value = root->get_slot({IMAP_FRAME_BAYES, foo, acct1_guid}); - EXPECT_EQ(1, value->get()); - value = root->get_slot({IMAP_FRAME_BAYES, bar, acct1_guid}); - EXPECT_EQ(1, value->get()); - value = root->get_slot({IMAP_FRAME_BAYES, baz, acct2_guid}); - EXPECT_EQ(1, value->get()); - value = root->get_slot({IMAP_FRAME_BAYES, waldo, acct2_guid}); - EXPECT_EQ(1, value->get()); - // 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, "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"}, 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"}, 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, foo, "Expense#Food"}, new KvpValue{*val2}); + 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({IMAP_FRAME_BAYES, pepper, acct3_guid}); + auto value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/severely/divided/token/" + acct3_guid}); EXPECT_EQ(10, value->get()); - // 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}); EXPECT_EQ(10, value->get()); - // 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}); EXPECT_EQ(5, value->get()); - // convert from 'Expense#Drink' to 'Drink' guid - value = root->get_slot({IMAP_FRAME_BAYES, sausage, acct2_guid}); - EXPECT_EQ(2, value->get()); - + value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + sausage + "/" + acct2_guid}); + /*We put in 2, then called it once to bring it up to 3.*/ + EXPECT_EQ(3, value->get()); // 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()); - - // Check for run once flag - auto vals = book->get_slot("changed-bayesian-to-guid"); - EXPECT_STREQ("true", vals->get()); - - EXPECT_EQ(1, qof_instance_get_editlevel(QOF_INSTANCE(t_bank_account))); + value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + foo + "/" + acct1_guid}); + EXPECT_EQ(5, value->get()); + // Keep GUID value from original + value = root->get_slot({std::string{IMAP_FRAME_BAYES} + "/" + salt + "/" + acct1_guid}); + EXPECT_EQ(10, value->get()); 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 ("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 ("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 (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"); +} diff --git a/libgnucash/engine/test/test-account-object.cpp b/libgnucash/engine/test/test-account-object.cpp index 2872f85fc5..32f612e65f 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 } +#include +#include "test-stuff.h" static void run_test (void) diff --git a/libgnucash/engine/test/test-kvp-frame.cpp b/libgnucash/engine/test/test-kvp-frame.cpp index 3df1c75a38..4a57c4560f 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()->get_slot("second")->get(); - second_frame->set("twenty", new KvpValue{new KvpFrame}); + auto second_frame = t_root.get_slot({"top"})->get()->get_slot({"second"})->get(); + 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()->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(); - 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,45 @@ 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()); } + +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-Account.cpp b/libgnucash/engine/test/utest-Account.cpp index 06dae62c04..4e59778b99 100644 --- a/libgnucash/engine/test/utest-Account.cpp +++ b/libgnucash/engine/test/utest-Account.cpp @@ -27,7 +27,6 @@ extern "C" #include #include #include -#include /* 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 #include typedef struct @@ -467,13 +467,7 @@ test_gnc_account_list_name_violations (Fixture *fixture, gconstpointer pData) { auto log_level = static_cast(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(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(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/libgnucash/engine/test/utest-Split.cpp b/libgnucash/engine/test/utest-Split.cpp index 815c2cac13..eafe1bb68e 100644 --- a/libgnucash/engine/test/utest-Split.cpp +++ b/libgnucash/engine/test/utest-Split.cpp @@ -35,7 +35,6 @@ extern "C" #include #include #include -#include #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 #include typedef struct @@ -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(const_cast(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); @@ -1797,7 +1797,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); @@ -1808,18 +1808,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 dde0a48582..c322c66f53 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,11 +881,11 @@ test_xaccTransEqual (Fixture *fixture, gconstpointer pData) g_free(clone->description); clone->description = static_cast(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); - 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)); @@ -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(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()); + auto txn_notes = g_strdup (frame->get_slot({trans_notes_str})->get()); 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(), ==, + g_assert_cmpstr (frame->get_slot({trans_notes_str})->get(), ==, "Voided transaction"); - g_assert_cmpstr (frame->get_slot(void_former_notes_str)->get(), + g_assert_cmpstr (frame->get_slot({void_former_notes_str})->get(), ==, txn_notes); - g_assert_cmpstr (frame->get_slot(void_reason_str)->get(), ==, + g_assert_cmpstr (frame->get_slot({void_reason_str})->get(), ==, void_reason); gnc_timespec_to_iso8601_buff (now, iso8601_str); - g_assert_cmpstr (frame->get_slot(void_time_str)->get(), ==, + g_assert_cmpstr (frame->get_slot({void_time_str})->get(), ==, iso8601_str); - g_assert_cmpstr (frame->get_slot(TRANS_READ_ONLY_REASON)->get(), + g_assert_cmpstr (frame->get_slot({TRANS_READ_ONLY_REASON})->get(), ==, "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(), ==, + g_assert_cmpstr (frame->get_slot({trans_notes_str})->get(), ==, 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(), + g_assert (guid_equal (frame->get_slot({TRANS_REVERSED_BY})->get(), xaccTransGetGUID (rev))); g_assert (!qof_instance_is_dirty (QOF_INSTANCE (rev))); //Cleared by commit diff --git a/po/POTFILES.in b/po/POTFILES.in index bced61f5a2..190bd219a6 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