diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index 5f293ab4bc..a17bec2008 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -1356,7 +1356,7 @@ xaccFreeAccount (Account *acc) PERR (" instead of calling xaccFreeAccount(), please call\n" " xaccAccountBeginEdit(); xaccAccountDestroy();\n"); - /* First, recursively free children */ + /* First, recursively free children, also frees list */ xaccFreeAccountChildren(acc); } @@ -6348,14 +6348,32 @@ gnc_account_delete_all_bayes_maps (Account *acc) /* ================================================================ */ /* QofObject function implementation and registration */ +static void +destroy_all_child_accounts (Account *acc, gpointer data) +{ + xaccAccountBeginEdit (acc); + xaccAccountDestroy (acc); +} + static void gnc_account_book_end(QofBook* book) { - Account *root_account = gnc_book_get_root_account(book); + Account *root_account = gnc_book_get_root_account (book); + GList *accounts; + if (!root_account) return; - xaccAccountBeginEdit(root_account); - xaccAccountDestroy(root_account); + + accounts = gnc_account_get_descendants (root_account); + + if (accounts) + { + accounts = g_list_reverse (accounts); + g_list_foreach (accounts, (GFunc)destroy_all_child_accounts, nullptr); + g_list_free (accounts); + } + xaccAccountBeginEdit (root_account); + xaccAccountDestroy (root_account); } #ifdef _MSC_VER diff --git a/libgnucash/engine/SX-book.c b/libgnucash/engine/SX-book.c index a7d185f16e..d30e405db2 100644 --- a/libgnucash/engine/SX-book.c +++ b/libgnucash/engine/SX-book.c @@ -180,7 +180,7 @@ static QofObject sxtg_object_def = { DI(.interface_version = ) QOF_OBJECT_VERSION, DI(.e_type = ) GNC_ID_SXTG, - DI(.type_label = ) "Scheduled Transaction Templates", + DI(.type_label = ) "Scheduled Transaction Group", DI(.create = ) NULL, DI(.book_begin = ) sxtg_book_begin, DI(.book_end = ) sxtg_book_end, @@ -281,7 +281,7 @@ book_sxes_end(QofBook* book) sxes = qof_collection_get_data(col); if (sxes != NULL) { - g_list_free (sxes->sx_list); + g_list_free(sxes->sx_list); g_object_unref(sxes); qof_collection_set_data(col, NULL); } diff --git a/libgnucash/engine/SchedXaction.c b/libgnucash/engine/SchedXaction.c index 127f452722..18d37ef6d8 100644 --- a/libgnucash/engine/SchedXaction.c +++ b/libgnucash/engine/SchedXaction.c @@ -32,6 +32,7 @@ #include "Account.h" #include "SX-book.h" +#include "SX-book-p.h" #include "SX-ttinfo.h" #include "SchedXaction.h" #include "Transaction.h" @@ -497,17 +498,8 @@ xaccSchedXactionFree( SchedXaction *sx ) delete_template_trans( sx ); - /* - * xaccAccountDestroy removes the account from - * its group for us AFAICT. If shutting down, - * the account is being deleted separately. - */ - - if (!qof_book_shutting_down(qof_instance_get_book(sx))) - { - xaccAccountBeginEdit(sx->template_acct); - xaccAccountDestroy(sx->template_acct); - } + xaccAccountBeginEdit( sx->template_acct ); + xaccAccountDestroy( sx->template_acct ); for ( l = sx->deferredList; l; l = l->next ) { @@ -1220,6 +1212,9 @@ gnc_sx_book_end(QofBook* book) col = qof_book_get_collection(book, GNC_ID_SCHEDXACTION); qof_collection_foreach(col, destroy_sx_on_book_close, NULL); + + // Now destroy the template root account + gnc_book_set_template_root (book, NULL); } #ifdef _MSC_VER diff --git a/libgnucash/engine/Transaction.c b/libgnucash/engine/Transaction.c index d8255f14c0..4b1888cc36 100644 --- a/libgnucash/engine/Transaction.c +++ b/libgnucash/engine/Transaction.c @@ -1788,7 +1788,7 @@ xaccTransRollbackEdit (Transaction *trans) xaccSplitRollbackEdit(s); SWAP_STR(s->action, so->action); SWAP_STR(s->memo, so->memo); - qof_instance_copy_kvp (QOF_INSTANCE (s), QOF_INSTANCE (so)); + qof_instance_copy_kvp (QOF_INSTANCE (s), QOF_INSTANCE (so)); s->reconciled = so->reconciled; s->amount = so->amount; s->value = so->value; @@ -1797,7 +1797,6 @@ xaccTransRollbackEdit (Transaction *trans) //SET_GAINS_A_VDIRTY(s); s->date_reconciled = so->date_reconciled; qof_instance_mark_clean(QOF_INSTANCE(s)); - xaccFreeSplit(so); } else { @@ -1824,6 +1823,10 @@ xaccTransRollbackEdit (Transaction *trans) } } g_list_free(slist); + + // orig->splits may still have duped splits so free them + for (node = orig->splits; node; node = node->next) + xaccFreeSplit(node->data); g_list_free(orig->splits); orig->splits = NULL; diff --git a/libgnucash/engine/gnc-commodity.c b/libgnucash/engine/gnc-commodity.c index 9799d9f79f..d40000ea38 100644 --- a/libgnucash/engine/gnc-commodity.c +++ b/libgnucash/engine/gnc-commodity.c @@ -38,6 +38,8 @@ #include "gnc-commodity.h" #include "gnc-locale-utils.h" #include "gnc-prefs.h" +#include "guid.h" +#include "qofinstance.h" static QofLogModule log_module = GNC_MOD_COMMODITY; @@ -1647,77 +1649,28 @@ gnc_commodity_equiv(const gnc_commodity * a, const gnc_commodity * b) priv_b = GET_PRIVATE(b); if (priv_a->name_space != priv_b->name_space) return FALSE; if (g_strcmp0(priv_a->mnemonic, priv_b->mnemonic) != 0) return FALSE; + return TRUE; } gboolean gnc_commodity_equal(const gnc_commodity * a, const gnc_commodity * b) { - gnc_commodityPrivate* priv_a; - gnc_commodityPrivate* priv_b; - gboolean same_book; - - if (a == b) return TRUE; - - if (!a || !b) - { - DEBUG ("one is NULL"); - return FALSE; - } - - priv_a = GET_PRIVATE(a); - priv_b = GET_PRIVATE(b); - same_book = qof_instance_get_book(QOF_INSTANCE(a)) == qof_instance_get_book(QOF_INSTANCE(b)); - - if ((same_book && priv_a->name_space != priv_b->name_space) - || (!same_book && g_strcmp0( gnc_commodity_namespace_get_name(priv_a->name_space), - gnc_commodity_namespace_get_name(priv_b->name_space)) != 0)) - { - DEBUG ("namespaces differ: %p(%s) vs %p(%s)", - priv_a->name_space, gnc_commodity_namespace_get_name(priv_a->name_space), - priv_b->name_space, gnc_commodity_namespace_get_name(priv_b->name_space)); - return FALSE; - } - - if (g_strcmp0(priv_a->mnemonic, priv_b->mnemonic) != 0) - { - DEBUG ("mnemonics differ: %s vs %s", priv_a->mnemonic, priv_b->mnemonic); - return FALSE; - } - - if (g_strcmp0(priv_a->fullname, priv_b->fullname) != 0) - { - DEBUG ("fullnames differ: %s vs %s", priv_a->fullname, priv_b->fullname); - return FALSE; - } - - if (g_strcmp0(priv_a->cusip, priv_b->cusip) != 0) - { - DEBUG ("cusips differ: %s vs %s", priv_a->cusip, priv_b->cusip); - return FALSE; - } - - if (priv_a->fraction != priv_b->fraction) - { - DEBUG ("fractions differ: %d vs %d", priv_a->fraction, priv_b->fraction); - return FALSE; - } - - return TRUE; + return gnc_commodity_compare(a, b) == 0; } +// Used as a sorting callback for deleting old prices, so it needs to be +// stable but doesn't need to be in any particular order sensible to humans. int gnc_commodity_compare(const gnc_commodity * a, const gnc_commodity * b) { - if (gnc_commodity_equal(a, b)) - { - return 0; - } - else - { - return 1; - } + if (a == b) return 0; + if (a && !b) return 1; + if (b && !a) return -1; + return qof_instance_guid_compare(a, b); } +// Used as a callback to g_list_find_custom, it should return 0 +// when the commodities match. int gnc_commodity_compare_void(const void * a, const void * b) { return gnc_commodity_compare(a, b); diff --git a/libgnucash/engine/gnc-pricedb.c b/libgnucash/engine/gnc-pricedb.c index 3d13ca3c8b..41e04023cc 100644 --- a/libgnucash/engine/gnc-pricedb.c +++ b/libgnucash/engine/gnc-pricedb.c @@ -2492,6 +2492,9 @@ convert_price (const gnc_commodity *from, const gnc_commodity *to, PriceTuple tu price = gnc_numeric_div (to_val, from_val, GNC_DENOM_AUTO, no_round); + gnc_price_unref (tuple.from); + gnc_price_unref (tuple.to); + if (from_cur == from && to_cur == to) return price; diff --git a/libgnucash/engine/gncBillTerm.c b/libgnucash/engine/gncBillTerm.c index e0abb5c047..604786a4fa 100644 --- a/libgnucash/engine/gncBillTerm.c +++ b/libgnucash/engine/gncBillTerm.c @@ -839,14 +839,28 @@ static void _gncBillTermCreate (QofBook *book) qof_book_set_data (book, _GNC_MOD_NAME, bi); } + +static void +destroy_billterm_on_book_close (QofInstance *ent, gpointer data) +{ + GncBillTerm *term = GNC_BILLTERM(ent); + + gncBillTermBeginEdit (term); + gncBillTermDestroy (term); +} + static void _gncBillTermDestroy (QofBook *book) { struct _book_info *bi; + QofCollection *col; if (!book) return; bi = qof_book_get_data (book, _GNC_MOD_NAME); + col = qof_book_get_collection (book, GNC_ID_BILLTERM); + qof_collection_foreach (col, destroy_billterm_on_book_close, NULL); + g_list_free (bi->terms); g_free (bi); } diff --git a/libgnucash/engine/gncCustomer.c b/libgnucash/engine/gncCustomer.c index 4ac50d888b..46f96edbf9 100644 --- a/libgnucash/engine/gncCustomer.c +++ b/libgnucash/engine/gncCustomer.c @@ -353,14 +353,17 @@ static void gncCustomerFree (GncCustomer *cust) gncAddressDestroy (cust->addr); gncAddressBeginEdit (cust->shipaddr); gncAddressDestroy (cust->shipaddr); + + gncJobFreeList (cust->jobs); g_list_free (cust->jobs); g_free (cust->balance); - if (cust->terms) - gncBillTermDecRef (cust->terms); - if (cust->taxtable) + if (!qof_book_shutting_down (qof_instance_get_book (QOF_INSTANCE(cust)))) { - gncTaxTableDecRef (cust->taxtable); + if (cust->terms) + gncBillTermDecRef (cust->terms); + if (cust->taxtable) + gncTaxTableDecRef (cust->taxtable); } /* qof_instance_release (&cust->inst); */ diff --git a/libgnucash/engine/gncEntry.c b/libgnucash/engine/gncEntry.c index 0350bc5735..78e6cd972d 100644 --- a/libgnucash/engine/gncEntry.c +++ b/libgnucash/engine/gncEntry.c @@ -463,10 +463,14 @@ static void gncEntryFree (GncEntry *entry) gncAccountValueDestroy (entry->i_tax_values); if (entry->b_tax_values) gncAccountValueDestroy (entry->b_tax_values); - if (entry->i_tax_table) - gncTaxTableDecRef (entry->i_tax_table); - if (entry->b_tax_table) - gncTaxTableDecRef (entry->b_tax_table); + + if (!qof_book_shutting_down (qof_instance_get_book (QOF_INSTANCE(entry)))) + { + if (entry->i_tax_table) + gncTaxTableDecRef (entry->i_tax_table); + if (entry->b_tax_table) + gncTaxTableDecRef (entry->b_tax_table); + } /* qof_instance_release (&entry->inst); */ g_object_unref (entry); diff --git a/libgnucash/engine/gncInvoice.c b/libgnucash/engine/gncInvoice.c index ab10dc1961..66a8f7fecd 100644 --- a/libgnucash/engine/gncInvoice.c +++ b/libgnucash/engine/gncInvoice.c @@ -435,10 +435,14 @@ static void gncInvoiceFree (GncInvoice *invoice) g_list_free (invoice->entries); g_list_free (invoice->prices); - if (invoice->printname) g_free (invoice->printname); + if (invoice->printname) + g_free (invoice->printname); - if (invoice->terms) - gncBillTermDecRef (invoice->terms); + if (!qof_book_shutting_down (qof_instance_get_book (QOF_INSTANCE(invoice)))) + { + if (invoice->terms) + gncBillTermDecRef (invoice->terms); + } if (invoice->doclink != is_unset) g_free (invoice->doclink); diff --git a/libgnucash/engine/gncJob.c b/libgnucash/engine/gncJob.c index 3b6689d56b..93cd66b52a 100644 --- a/libgnucash/engine/gncJob.c +++ b/libgnucash/engine/gncJob.c @@ -231,6 +231,18 @@ GncJob *gncJobCreate (QofBook *book) return job; } +static void free_job_list (GncJob *job) +{ + gncJobBeginEdit (job); + gncJobDestroy (job); +} + +void gncJobFreeList (GList *jobs) +{ + GList *job_list = g_list_copy (jobs); + g_list_free_full (job_list, (GDestroyNotify)free_job_list); +} + void gncJobDestroy (GncJob *job) { if (!job) return; diff --git a/libgnucash/engine/gncJob.h b/libgnucash/engine/gncJob.h index 1642dfdbc9..2e67ca2b9c 100644 --- a/libgnucash/engine/gncJob.h +++ b/libgnucash/engine/gncJob.h @@ -61,6 +61,7 @@ GType gnc_job_get_type(void); GncJob *gncJobCreate (QofBook *book); void gncJobDestroy (GncJob *job); +void gncJobFreeList (GList *jobs); /** \name Set Functions @{ diff --git a/libgnucash/engine/gncTaxTable.c b/libgnucash/engine/gncTaxTable.c index fca6cc1fa4..9ffd37720b 100644 --- a/libgnucash/engine/gncTaxTable.c +++ b/libgnucash/engine/gncTaxTable.c @@ -1015,14 +1015,27 @@ static void _gncTaxTableCreate (QofBook *book) qof_book_set_data (book, _GNC_MOD_NAME, bi); } +static void +destroy_taxtable_on_book_close (QofInstance *ent, gpointer data) +{ + GncTaxTable *table = GNC_TAXTABLE(ent); + + gncTaxTableBeginEdit (table); + gncTaxTableDestroy (table); +} + static void _gncTaxTableDestroy (QofBook *book) { struct _book_info *bi; + QofCollection *col; if (!book) return; bi = qof_book_get_data (book, _GNC_MOD_NAME); + col = qof_book_get_collection (book, GNC_ID_TAXTABLE); + qof_collection_foreach (col, destroy_taxtable_on_book_close, NULL); + g_list_free (bi->tables); g_free (bi); } diff --git a/libgnucash/engine/gncVendor.c b/libgnucash/engine/gncVendor.c index e6518125e4..62a42bf03a 100644 --- a/libgnucash/engine/gncVendor.c +++ b/libgnucash/engine/gncVendor.c @@ -496,13 +496,18 @@ static void gncVendorFree (GncVendor *vendor) CACHE_REMOVE (vendor->notes); gncAddressBeginEdit (vendor->addr); gncAddressDestroy (vendor->addr); + + gncJobFreeList (vendor->jobs); g_list_free (vendor->jobs); g_free (vendor->balance); - if (vendor->terms) - gncBillTermDecRef (vendor->terms); - if (vendor->taxtable) - gncTaxTableDecRef (vendor->taxtable); + if (!qof_book_shutting_down (qof_instance_get_book (QOF_INSTANCE(vendor)))) + { + if (vendor->terms) + gncBillTermDecRef (vendor->terms); + if (vendor->taxtable) + gncTaxTableDecRef (vendor->taxtable); + } /* qof_instance_release (&vendor->inst); */ g_object_unref (vendor);