diff --git a/libgnucash/engine/Account.cpp b/libgnucash/engine/Account.cpp index 8f12f0c64d..78755e38d5 100644 --- a/libgnucash/engine/Account.cpp +++ b/libgnucash/engine/Account.cpp @@ -262,34 +262,29 @@ gchar *gnc_account_name_violations_errmsg (const gchar *separator, GList* invali return message; } -GList *gnc_account_list_name_violations (QofBook *book, const gchar *separator) +struct ViolationData { - Account *root_account = gnc_book_get_root_account(book); - GList *accounts, *node; - GList *invalid_list = NULL; - - g_return_val_if_fail (separator != NULL, NULL); - - if (root_account == NULL) - return NULL; - - accounts = gnc_account_get_descendants (root_account); - for (node = accounts; node; node = g_list_next(node)) - { - Account *acct = (Account*)node->data; - gchar *acct_name = g_strdup ( xaccAccountGetName ( acct ) ); + GList *list; + const gchar *separator; +}; - if ( g_strstr_len ( acct_name, -1, separator ) ) - invalid_list = g_list_prepend ( invalid_list, (gpointer) acct_name ); - else - g_free ( acct_name ); - } - if (accounts != NULL) - { - g_list_free(accounts); - } +static void +check_acct_name (Account *acct, gpointer user_data) +{ + auto cb {static_cast(user_data)}; + auto name {xaccAccountGetName (acct)}; + if (g_strstr_len (name, -1, cb->separator)) + cb->list = g_list_prepend (cb->list, g_strdup (name)); +} - return invalid_list; +GList *gnc_account_list_name_violations (QofBook *book, const gchar *separator) +{ + g_return_val_if_fail (separator != NULL, nullptr); + if (!book) return nullptr; + ViolationData cb = { nullptr, separator }; + gnc_account_foreach_descendant (gnc_book_get_root_account (book), + (AccountCb)check_acct_name, &cb); + return cb.list; } /********************************************************************\ @@ -2691,6 +2686,35 @@ DxaccAccountSetCurrency (Account * acc, gnc_commodity * currency) /********************************************************************\ \********************************************************************/ +static void +account_foreach_descendant (const Account *acc, AccountCb thunk, + void* user_data, bool sort) +{ + GList *children; + + g_return_if_fail (GNC_IS_ACCOUNT(acc)); + g_return_if_fail (thunk); + + auto priv{GET_PRIVATE(acc)}; + if (sort) + { + children = g_list_copy (priv->children); + children = g_list_sort (children, (GCompareFunc)xaccAccountOrder); + } + else + children = priv->children; + + for (auto node = children; node; node = node->next) + { + auto child = static_cast(node->data); + thunk (child, user_data); + account_foreach_descendant (child, thunk, user_data, sort); + } + + if (sort) + g_list_free (children); +} + void gnc_account_append_child (Account *new_parent, Account *child) { @@ -2864,20 +2888,18 @@ gnc_account_nth_child (const Account *parent, gint num) return static_cast(g_list_nth_data(GET_PRIVATE(parent)->children, num)); } +static void +count_acct (Account *account, gpointer user_data) +{ + auto count {static_cast(user_data)}; + ++*count; +} + gint gnc_account_n_descendants (const Account *account) { - AccountPrivate *priv; - GList *node; - gint count = 0; - - g_return_val_if_fail(GNC_IS_ACCOUNT(account), 0); - - priv = GET_PRIVATE(account); - for (node = priv->children; node; node = g_list_next(node)) - { - count += gnc_account_n_descendants(static_cast(node->data)) + 1; - } + int count {0}; + account_foreach_descendant (account, count_acct, &count, FALSE); return count; } @@ -2921,118 +2943,53 @@ gnc_account_get_tree_depth (const Account *account) return depth + 1; } +static void +collect_acct (Account *account, gpointer user_data) +{ + auto listptr{static_cast(user_data)}; + *listptr = g_list_prepend (*listptr, account); +} + GList * gnc_account_get_descendants (const Account *account) { - AccountPrivate *priv; - GList *child, *descendants; - - g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL); - - priv = GET_PRIVATE(account); - if (!priv->children) - return NULL; - - descendants = NULL; - for (child = priv->children; child; child = g_list_next(child)) - { - descendants = g_list_append(descendants, child->data); - descendants = g_list_concat(descendants, - gnc_account_get_descendants(static_cast(child->data))); - } - return descendants; + GList* list = nullptr; + account_foreach_descendant (account, collect_acct, &list, FALSE); + return g_list_reverse (list); } GList * gnc_account_get_descendants_sorted (const Account *account) { - AccountPrivate *priv; - GList *child, *children, *descendants; - - /* errors */ - g_return_val_if_fail(GNC_IS_ACCOUNT(account), NULL); - - /* optimizations */ - priv = GET_PRIVATE(account); - if (!priv->children) - return NULL; + GList* list = nullptr; + account_foreach_descendant (account, collect_acct, &list, TRUE); + return g_list_reverse (list); +} - descendants = NULL; - children = g_list_sort(g_list_copy(priv->children), (GCompareFunc)xaccAccountOrder); - for (child = children; child; child = g_list_next(child)) - { - descendants = g_list_append(descendants, child->data); - descendants = g_list_concat(descendants, - gnc_account_get_descendants_sorted(static_cast(child->data))); - } - g_list_free(children); - return descendants; +static gpointer +is_acct_name (Account *account, gpointer user_data) +{ + auto name {static_cast(user_data)}; + return (g_strcmp0 (name, xaccAccountGetName (account)) ? nullptr : account); } Account * gnc_account_lookup_by_name (const Account *parent, const char * name) { - AccountPrivate *cpriv, *ppriv; - Account *child, *result; - GList *node; - - g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL); - g_return_val_if_fail(name, NULL); - - /* first, look for accounts hanging off the current node */ - ppriv = GET_PRIVATE(parent); - for (node = ppriv->children; node; node = node->next) - { - child = static_cast(node->data); - cpriv = GET_PRIVATE(child); - if (g_strcmp0(cpriv->accountName, name) == 0) - return child; - } - - /* if we are still here, then we haven't found the account yet. - * Recursively search each of the child accounts next */ - for (node = ppriv->children; node; node = node->next) - { - child = static_cast(node->data); - result = gnc_account_lookup_by_name (child, name); - if (result) - return result; - } + return (Account*)gnc_account_foreach_descendant_until (parent, is_acct_name, (char*)name); +} - return NULL; +static gpointer +is_acct_code (Account *account, gpointer user_data) +{ + auto name {static_cast(user_data)}; + return (g_strcmp0 (name, xaccAccountGetCode (account)) ? nullptr : account); } Account * gnc_account_lookup_by_code (const Account *parent, const char * code) { - AccountPrivate *cpriv, *ppriv; - Account *child, *result; - GList *node; - - g_return_val_if_fail(GNC_IS_ACCOUNT(parent), NULL); - g_return_val_if_fail(code, NULL); - - /* first, look for accounts hanging off the current node */ - ppriv = GET_PRIVATE(parent); - for (node = ppriv->children; node; node = node->next) - { - child = static_cast(node->data); - cpriv = GET_PRIVATE(child); - if (g_strcmp0(cpriv->accountCode, code) == 0) - return child; - } - - /* if we are still here, then we haven't found the account yet. - * Recursively search each of the child accounts next */ - for (node = ppriv->children; node; node = node->next) - { - child = static_cast(node->data); - result = gnc_account_lookup_by_code (child, code); - if (result) - return result; - } - - return NULL; + return (Account*)gnc_account_foreach_descendant_until (parent, is_acct_code, (char*)code); } static gpointer @@ -3183,20 +3140,7 @@ gnc_account_foreach_descendant (const Account *acc, AccountCb thunk, gpointer user_data) { - const AccountPrivate *priv; - GList *node; - Account *child; - - g_return_if_fail(GNC_IS_ACCOUNT(acc)); - g_return_if_fail(thunk); - - priv = GET_PRIVATE(acc); - for (node = priv->children; node; node = node->next) - { - child = static_cast(node->data); - thunk(child, user_data); - gnc_account_foreach_descendant(child, thunk, user_data); - } + account_foreach_descendant (acc, thunk, user_data, FALSE); } gpointer @@ -3204,28 +3148,24 @@ gnc_account_foreach_descendant_until (const Account *acc, AccountCb2 thunk, gpointer user_data) { - const AccountPrivate *priv; - GList *node; - Account *child; - gpointer result; + gpointer result {nullptr}; - g_return_val_if_fail(GNC_IS_ACCOUNT(acc), NULL); - g_return_val_if_fail(thunk, NULL); + g_return_val_if_fail (GNC_IS_ACCOUNT(acc), nullptr); + g_return_val_if_fail (thunk, nullptr); - priv = GET_PRIVATE(acc); - for (node = priv->children; node; node = node->next) + auto priv{GET_PRIVATE(acc)}; + + for (auto node = priv->children; node; node = node->next) { - child = static_cast(node->data); - result = thunk(child, user_data); - if (result) - return(result); - - result = gnc_account_foreach_descendant_until(child, thunk, user_data); - if (result) - return(result); + auto child = static_cast(node->data); + result = thunk (child, user_data); + if (result) break; + + result = gnc_account_foreach_descendant_until (child, thunk, user_data); + if (result) break; } - return NULL; + return result; }