mirror of
https://github.com/Gnucash/gnucash.git
synced 2026-10-16 11:22:00 -05:00
Date: Sun, 17 Oct 1999 18:01:53 -0700 git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@1936 57a11ea4-9604-0410-9ed3-97b8803252fd
894 lines
23 KiB
C
894 lines
23 KiB
C
/********************************************************************\
|
|
* Group.c -- the main data structure of the program *
|
|
* Copyright (C) 1997 Robin D. Clark *
|
|
* Copyright (C) 1997, 1998 Linas Vepstas *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU General Public License as *
|
|
* published by the Free Software Foundation; either version 2 of *
|
|
* the License, or (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License*
|
|
* along with this program; if not, write to the Free Software *
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
|
* *
|
|
* Author: Rob Clark *
|
|
* Internet: rclark@cs.hmc.edu *
|
|
* Address: 609 8th Street *
|
|
* Huntington Beach, CA 92648-4632 *
|
|
\********************************************************************/
|
|
|
|
#include <assert.h>
|
|
|
|
#include "config.h"
|
|
|
|
#include "Account.h"
|
|
#include "AccountP.h"
|
|
#include "Group.h"
|
|
#include "GroupP.h"
|
|
#include "TransactionP.h"
|
|
#include "util.h"
|
|
#include "gnc-common.h"
|
|
|
|
/********************************************************************\
|
|
* Because I can't use C++ for this project, doesn't mean that I *
|
|
* can't pretend to! These functions perform actions on the *
|
|
* AccountGroup data structure, in order to encapsulate the *
|
|
* knowledge of the internals of the AccountGroup in one file. *
|
|
\********************************************************************/
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
void
|
|
xaccInitializeAccountGroup (AccountGroup *grp)
|
|
{
|
|
grp->saved = GNC_T;
|
|
|
|
grp->parent = NULL;
|
|
grp->numAcc = 0;
|
|
grp->account = _malloc (sizeof (Account *));
|
|
grp->account[0] = NULL; /* null-terminated array */
|
|
|
|
grp->balance = 0.0;
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
AccountGroup *
|
|
xaccMallocAccountGroup( void )
|
|
{
|
|
AccountGroup *grp = (AccountGroup *)_malloc(sizeof(AccountGroup));
|
|
|
|
xaccInitializeAccountGroup (grp);
|
|
|
|
return grp;
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
void
|
|
xaccFreeAccountGroup( AccountGroup *grp )
|
|
{
|
|
int i;
|
|
if (NULL == grp) return;
|
|
|
|
for( i=0; i<grp->numAcc; i++ ) {
|
|
xaccFreeAccount( grp->account[i] );
|
|
}
|
|
|
|
_free( grp->account );
|
|
|
|
/* null everything out, just in case somebody
|
|
* tries to traverse freed memory */
|
|
grp->parent = NULL;
|
|
grp->numAcc = 0;
|
|
grp->account = NULL;
|
|
grp->balance = 0.0;
|
|
|
|
_free(grp);
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
void
|
|
xaccAccountGroupMarkSaved (AccountGroup *grp)
|
|
{
|
|
int i;
|
|
|
|
if (!grp) return;
|
|
grp->saved = GNC_T;
|
|
|
|
for (i=0; i<grp->numAcc; i++) {
|
|
xaccAccountGroupMarkSaved (grp->account[i]->children);
|
|
}
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
int
|
|
xaccAccountGroupNotSaved (AccountGroup *grp)
|
|
{
|
|
int not_saved;
|
|
int i;
|
|
|
|
if (!grp) return 0;
|
|
if (GNC_F == grp->saved) return 1;
|
|
|
|
for (i=0; i<grp->numAcc; i++) {
|
|
not_saved = xaccAccountGroupNotSaved (grp->account[i]->children);
|
|
if (not_saved) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/********************************************************************\
|
|
* Get the number of accounts, including subaccounts *
|
|
\********************************************************************/
|
|
|
|
int
|
|
xaccGetNumAccounts ( AccountGroup *root )
|
|
{
|
|
int num_acc = 0;
|
|
int i;
|
|
|
|
if (NULL == root) return 0;
|
|
|
|
num_acc = root->numAcc;
|
|
|
|
for (i=0; i<root->numAcc; i++) {
|
|
num_acc += xaccGetNumAccounts (root->account[i]->children);
|
|
}
|
|
|
|
return num_acc;
|
|
}
|
|
|
|
/********************************************************************\
|
|
* Get all of the accounts, including subaccounts *
|
|
\********************************************************************/
|
|
|
|
int
|
|
xaccFillInAccounts ( AccountGroup *root, Account **arr )
|
|
{
|
|
int num_acc = 0;
|
|
int i,j;
|
|
|
|
if (!root || !arr) return 0;
|
|
|
|
num_acc = root->numAcc;
|
|
for (i=0, j=0; i<num_acc; i++) {
|
|
arr[j] = root->account[i];
|
|
j++;
|
|
j += xaccFillInAccounts (root->account[i]->children, &arr[j]);
|
|
}
|
|
|
|
arr[j] = NULL;
|
|
return j;
|
|
}
|
|
|
|
Account **
|
|
xaccGetAccounts ( AccountGroup *root )
|
|
{
|
|
Account **arr;
|
|
int num_acc = 0;
|
|
int num_done;
|
|
|
|
if (NULL == root) return NULL;
|
|
|
|
num_acc = xaccGetNumAccounts (root);
|
|
arr = (Account **) malloc ((num_acc+1)*sizeof (Account *));
|
|
|
|
num_done = xaccFillInAccounts (root, arr);
|
|
assert (num_done == num_acc);
|
|
|
|
arr[num_acc] = NULL;
|
|
return arr;
|
|
}
|
|
|
|
/********************************************************************\
|
|
* Fetch an account, given only its ID number *
|
|
\********************************************************************/
|
|
|
|
Account *
|
|
xaccGetAccountFromID ( AccountGroup *root, int acc_id )
|
|
{
|
|
Account *acc;
|
|
int i;
|
|
|
|
if (NULL == root) return NULL;
|
|
if (0 > acc_id) return NULL;
|
|
|
|
/* first, look for accounts hanging off the root */
|
|
for (i=0; i<root->numAcc; i++) {
|
|
acc = root->account[i];
|
|
if (acc_id == acc->id) return acc;
|
|
}
|
|
|
|
/* if we are still here, then we haven't found the account yet.
|
|
* Recursively search the subgroups next */
|
|
for (i=0; i<root->numAcc; i++) {
|
|
acc = xaccGetAccountFromID (root->account[i]->children, acc_id);
|
|
if (acc) return acc;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/********************************************************************\
|
|
* Fetch the root of the tree *
|
|
\********************************************************************/
|
|
|
|
AccountGroup *
|
|
xaccGetAccountRoot (Account * acc)
|
|
{
|
|
Account *parent_acc;
|
|
AccountGroup * grp;
|
|
AccountGroup * root = NULL;
|
|
|
|
if (!acc) return NULL;
|
|
|
|
/* find the root of the account group structure */
|
|
grp = (AccountGroup *) acc->parent;
|
|
while (grp) {
|
|
root = grp;
|
|
parent_acc = grp -> parent;
|
|
grp = NULL;
|
|
if (parent_acc) {
|
|
grp = (AccountGroup *) parent_acc->parent;
|
|
}
|
|
}
|
|
return root;
|
|
}
|
|
|
|
/********************************************************************\
|
|
* Fetch an account, given only its ID number *
|
|
\********************************************************************/
|
|
|
|
Account *
|
|
xaccGetPeerAccountFromID ( Account *acc, int acc_id )
|
|
{
|
|
AccountGroup * root;
|
|
Account *peer_acc;
|
|
|
|
if (NULL == acc) return NULL;
|
|
if (-1 >= acc_id) return NULL;
|
|
|
|
/* first, find the root of the account group structure */
|
|
root = xaccGetAccountRoot (acc);
|
|
|
|
/* now search all acounts hanging off the root */
|
|
peer_acc = xaccGetAccountFromID (root, acc_id);
|
|
|
|
return peer_acc;
|
|
}
|
|
|
|
/********************************************************************\
|
|
* Fetch an account, given its name *
|
|
\********************************************************************/
|
|
|
|
Account *
|
|
xaccGetAccountFromName ( AccountGroup *root, const char * name )
|
|
{
|
|
Account *acc;
|
|
int i;
|
|
|
|
if (NULL == root) return NULL;
|
|
if (NULL == name) return NULL;
|
|
|
|
/* first, look for accounts hanging off the root */
|
|
for (i=0; i<root->numAcc; i++) {
|
|
acc = root->account[i];
|
|
if (!safe_strcmp(acc->accountName, name)) return acc;
|
|
}
|
|
|
|
/* if we are still here, then we haven't found the account yet.
|
|
* Recursively search the subgroups next */
|
|
for (i=0; i<root->numAcc; i++) {
|
|
acc = xaccGetAccountFromName (root->account[i]->children, name);
|
|
if (acc) return acc;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/********************************************************************\
|
|
* Fetch an account, given its name *
|
|
\********************************************************************/
|
|
|
|
Account *
|
|
xaccGetPeerAccountFromName ( Account *acc, const char * name )
|
|
{
|
|
AccountGroup * root;
|
|
Account *peer_acc;
|
|
|
|
if (NULL == acc) return NULL;
|
|
if (NULL == name) return NULL;
|
|
|
|
/* first, find the root of the account group structure */
|
|
root = xaccGetAccountRoot (acc);
|
|
|
|
/* now search all acounts hanging off the root */
|
|
peer_acc = xaccGetAccountFromName (root, name);
|
|
|
|
return peer_acc;
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
void
|
|
xaccRemoveGroup (AccountGroup *grp)
|
|
{
|
|
Account *acc;
|
|
|
|
if (NULL == grp) return;
|
|
acc = grp->parent;
|
|
|
|
/* if this group has no parent, it must be the topgroup */
|
|
if (NULL == acc) return;
|
|
|
|
acc->children = NULL;
|
|
|
|
/* make sure that the parent of the group is marked
|
|
* as having been modified. */
|
|
grp = acc -> parent;
|
|
if (!grp) return;
|
|
|
|
grp->saved = GNC_F;
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
void
|
|
xaccRemoveAccount (Account *acc)
|
|
{
|
|
int i,j, nacc;
|
|
AccountGroup *grp;
|
|
Account **arr;
|
|
|
|
if (NULL == acc) return;
|
|
grp = acc->parent;
|
|
acc->parent = NULL;
|
|
|
|
/* this routine might be called on accounts which
|
|
* are not yet parented. */
|
|
if (NULL == grp) return;
|
|
|
|
nacc = grp->numAcc;
|
|
assert (nacc);
|
|
|
|
arr = grp->account;
|
|
|
|
for( i=0,j=0; j<nacc; i++,j++ ) {
|
|
arr[i] = arr[j];
|
|
if( acc == arr[j] ) { i--; }
|
|
}
|
|
nacc --;
|
|
arr[nacc] = NULL;
|
|
grp->numAcc = nacc;
|
|
grp->saved = GNC_F;
|
|
|
|
/* if this was the last account in a group, delete
|
|
* the group as well (unless its a root group) */
|
|
if ((0 == nacc) && (grp->parent)) {
|
|
xaccRemoveGroup (grp);
|
|
xaccFreeAccountGroup (grp);
|
|
}
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
void
|
|
xaccInsertSubAccount( Account *adult, Account *child )
|
|
{
|
|
if (NULL == adult) return;
|
|
|
|
/* if a container for the children doesn't yet exist, add it */
|
|
if (NULL == adult->children) {
|
|
adult->children = xaccMallocAccountGroup();
|
|
}
|
|
|
|
/* set back-pointer to parent */
|
|
adult->children->parent = adult;
|
|
|
|
/* allow side-effect of creating a child-less account group */
|
|
if (NULL == child) return;
|
|
|
|
xaccGroupInsertAccount (adult->children, child);
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
void
|
|
xaccGroupInsertAccount( AccountGroup *grp, Account *acc )
|
|
{
|
|
int i,nacc;
|
|
Account **arr;
|
|
int ralo = 1;
|
|
|
|
if (NULL == grp) return;
|
|
if (NULL == acc) return;
|
|
|
|
/* If the account is currently in another group, remove it there first.
|
|
* Basically, we can't have accounts being in two places at once.
|
|
* If old and new parents are the same, reinsertion causes the sort order
|
|
* to be checked.
|
|
*/
|
|
if (acc->parent) {
|
|
if (grp == acc->parent) ralo = 0;
|
|
xaccRemoveAccount (acc);
|
|
}
|
|
grp->saved = GNC_F;
|
|
|
|
/* set back-pointer to the accounts parent */
|
|
acc->parent = grp;
|
|
|
|
nacc = grp->numAcc;
|
|
arr = grp->account;
|
|
if (ralo) {
|
|
arr = (Account **) realloc (arr, (nacc+2)*sizeof(Account *));
|
|
}
|
|
|
|
/* insert account in proper sort order */
|
|
for (i=nacc; i>=0; i--) {
|
|
if ((0<i) && (0 < xaccAccountOrder (&(arr[i-1]), &acc))) {
|
|
arr[i] = arr[i-1];
|
|
} else {
|
|
arr[i] = acc;
|
|
break;
|
|
}
|
|
}
|
|
|
|
nacc++;
|
|
arr[nacc] = NULL;
|
|
grp->account = arr;
|
|
grp->numAcc = nacc;
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
void
|
|
xaccRecomputeGroupBalance (AccountGroup *grp)
|
|
{
|
|
int i;
|
|
Account *acc;
|
|
char * default_currency;
|
|
|
|
if (!grp) return;
|
|
if (!(grp->account)) return;
|
|
|
|
acc = grp->account[0];
|
|
if (!acc) return;
|
|
default_currency = acc->currency;
|
|
|
|
grp->balance = 0.0;
|
|
for (i=0; i<grp->numAcc; i++) {
|
|
acc = grp->account[i];
|
|
|
|
/* first, get subtotals recursively */
|
|
if (acc->children) {
|
|
xaccRecomputeGroupBalance (acc->children);
|
|
|
|
if (!safe_strcmp (default_currency, acc->currency)) {
|
|
grp->balance += acc->children->balance;
|
|
}
|
|
}
|
|
|
|
/* then add up accounts in this group */
|
|
xaccAccountRecomputeBalance (acc);
|
|
if (!safe_strcmp (default_currency, acc->currency)) {
|
|
grp->balance += acc->balance;
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
/* account codes will be assigned base-36, with three digits */
|
|
|
|
#define BASE 36
|
|
|
|
char *
|
|
xaccGroupGetNextFreeCode (AccountGroup *grp, int digits)
|
|
{
|
|
Account *acc;
|
|
int i, maxcode = 0;
|
|
char * retval;
|
|
|
|
if (!grp) return NULL;
|
|
|
|
/* count levels to top */
|
|
acc = grp->parent;
|
|
while (acc) {
|
|
digits --;
|
|
assert (acc->parent);
|
|
acc = acc->parent->parent;
|
|
}
|
|
|
|
/* if (0>digits) we could insert a decimal place, but I am too lazy
|
|
* to write this code. It doesn't seem important at the moment ... */
|
|
|
|
/* find the largest used code */
|
|
acc = grp->parent;
|
|
if (acc) {
|
|
if (acc->accountCode) {
|
|
maxcode = strtol (acc->accountCode, NULL, BASE);
|
|
}
|
|
}
|
|
for (i=0; i<grp->numAcc; i++) {
|
|
Account *acnt = grp->account[i];
|
|
if (acnt->accountCode) {
|
|
int code = strtol (acnt->accountCode, NULL, BASE);
|
|
if (code > maxcode) maxcode = code;
|
|
}
|
|
}
|
|
|
|
/* right-shift */
|
|
for (i=1; i<digits; i++) {
|
|
maxcode /= BASE;
|
|
}
|
|
maxcode ++;
|
|
|
|
/* left-shift */
|
|
for (i=1; i<digits; i++) {
|
|
maxcode *= BASE;
|
|
}
|
|
|
|
/* print */
|
|
retval = ultostr ((unsigned long) maxcode, BASE);
|
|
return retval;
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
/* almost identical code to above, but altered to deal with
|
|
* specified account */
|
|
|
|
char *
|
|
xaccAccountGetNextChildCode (Account *parent_acc, int digits)
|
|
{
|
|
Account *acc;
|
|
int i, maxcode = 0;
|
|
char * retval;
|
|
AccountGroup *grp;
|
|
|
|
if (!parent_acc) return NULL;
|
|
|
|
/* count levels to top */
|
|
acc = parent_acc;
|
|
while (acc) {
|
|
digits --;
|
|
assert (acc->parent); /* all acounts must be in a group */
|
|
acc = acc->parent->parent;
|
|
}
|
|
|
|
/* if (0>digits) we could insert a decimal place, but I am too lazy
|
|
* to write this code. It doesn't seem important at the moment ... */
|
|
|
|
/* find the largest used code */
|
|
acc = parent_acc;
|
|
if (acc) {
|
|
if (acc->accountCode) {
|
|
maxcode = strtol (acc->accountCode, NULL, BASE);
|
|
}
|
|
}
|
|
grp = parent_acc->children;
|
|
if (grp) {
|
|
for (i=0; i<grp->numAcc; i++) {
|
|
Account *acnt = grp->account[i];
|
|
if (acnt->accountCode) {
|
|
int code = strtol (acnt->accountCode, NULL, BASE);
|
|
if (code > maxcode) maxcode = code;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* right-shift */
|
|
for (i=1; i<digits; i++) {
|
|
maxcode /= BASE;
|
|
}
|
|
maxcode ++;
|
|
|
|
/* left-shift */
|
|
for (i=1; i<digits; i++) {
|
|
maxcode *= BASE;
|
|
}
|
|
|
|
/* print */
|
|
retval = ultostr ((unsigned long) maxcode, BASE);
|
|
return retval;
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
void
|
|
xaccGroupDepthAutoCode (AccountGroup *grp)
|
|
{
|
|
int depth;
|
|
if (!grp) return;
|
|
|
|
/* get the depth */
|
|
depth = xaccGroupGetDepth (grp);
|
|
if (3>depth) depth = 3;
|
|
|
|
xaccGroupAutoCode (grp, depth);
|
|
}
|
|
|
|
void
|
|
xaccGroupAutoCode (AccountGroup *grp, int depth)
|
|
{
|
|
int i, n;
|
|
if (!grp || (0>depth)) return;
|
|
|
|
n = grp->numAcc;
|
|
for (i=0; i<n; i++) {
|
|
Account *acc = grp->account[i];
|
|
xaccAccountAutoCode (acc, depth);
|
|
xaccGroupAutoCode (acc->children, depth);
|
|
}
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
void
|
|
xaccConcatGroups (AccountGroup *togrp, AccountGroup *fromgrp)
|
|
{
|
|
Account * acc;
|
|
int numAcc;
|
|
|
|
if (!togrp) return;
|
|
if (!fromgrp) return;
|
|
|
|
/* The act of inserting the account into togrp also causes
|
|
* it to automatically be deleted from fromgrp. But use a
|
|
* saved copy of fromgrp's numAcc member since, after the
|
|
* last insertion, fromgrp will be pointing to freed memory.
|
|
*/
|
|
numAcc = fromgrp->numAcc;
|
|
while (numAcc) {
|
|
acc = fromgrp->account[0];
|
|
xaccGroupInsertAccount (togrp, acc);
|
|
numAcc--;
|
|
}
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
void
|
|
xaccMergeAccounts (AccountGroup *grp)
|
|
{
|
|
Account *acc_a, *acc_b;
|
|
int i, j, k;
|
|
|
|
if (!grp) return;
|
|
|
|
for (i=0; i<grp->numAcc; i++) {
|
|
acc_a = grp->account[i];
|
|
for (j=i+1; j<grp->numAcc; j++) {
|
|
acc_b = grp->account[j];
|
|
if ((0 == safe_strcmp(acc_a->accountName, acc_b->accountName)) &&
|
|
(0 == safe_strcmp(acc_a->accountCode, acc_b->accountCode)) &&
|
|
(0 == safe_strcmp(acc_a->description, acc_b->description)) &&
|
|
(0 == safe_strcmp(acc_a->currency, acc_b->currency)) &&
|
|
(0 == safe_strcmp(acc_a->security, acc_b->security)) &&
|
|
(0 == safe_strcmp(acc_a->notes, acc_b->notes)) &&
|
|
(acc_a->type == acc_b->type)) {
|
|
|
|
AccountGroup *ga, *gb;
|
|
|
|
/* consolidate children */
|
|
ga = (AccountGroup *) acc_a->children;
|
|
gb = (AccountGroup *) acc_b->children;
|
|
if (gb) {
|
|
if (!ga) {
|
|
acc_a->children = gb;
|
|
gb->parent = acc_a;
|
|
acc_b->children = NULL;
|
|
} else {
|
|
xaccConcatGroups (ga, gb);
|
|
acc_b->children = NULL;
|
|
/* XXX why is the below commented out ??? */
|
|
/* xaccFreeAccountGroup (gb); XXX ??? */
|
|
}
|
|
}
|
|
|
|
/* recurse to do the children's children */
|
|
xaccMergeAccounts (ga);
|
|
|
|
/* consolidate transactions */
|
|
for (k=0; k<acc_b->numSplits; k++) {
|
|
Split *split;
|
|
split = acc_b->splits[k];
|
|
acc_b->splits[k] = NULL;
|
|
split->acc = NULL;
|
|
xaccAccountInsertSplit (acc_a, split);
|
|
}
|
|
|
|
/* free the account structure itself */
|
|
acc_b->numSplits = 0;
|
|
xaccFreeAccount (acc_b);
|
|
grp->account[j] = grp->account[grp->numAcc -1];
|
|
grp->account[grp->numAcc -1] = NULL;
|
|
grp->numAcc --;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
void
|
|
xaccConsolidateGrpTransactions (AccountGroup *grp)
|
|
{
|
|
Account * acc;
|
|
int i;
|
|
|
|
if (!grp) return;
|
|
|
|
for (i=0; i<grp->numAcc; i++) {
|
|
acc = grp->account[i];
|
|
xaccConsolidateTransactions (acc);
|
|
|
|
/* recursively do the children */
|
|
xaccConsolidateGrpTransactions (acc->children);
|
|
}
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
int
|
|
xaccGroupGetNumAccounts (AccountGroup *grp)
|
|
{
|
|
if (!grp) return 0;
|
|
return (grp->numAcc);
|
|
}
|
|
|
|
Account *
|
|
xaccGroupGetAccount (AccountGroup *grp, int i)
|
|
{
|
|
if (!grp) return NULL;
|
|
if (!(grp->account)) return NULL;
|
|
if((0>i) || (i >= grp->numAcc)) return NULL;
|
|
return (grp->account[i]);
|
|
}
|
|
|
|
double
|
|
xaccGroupGetBalance (AccountGroup * grp)
|
|
{
|
|
if (!grp) return 0.0;
|
|
return (grp->balance);
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
int
|
|
xaccGroupGetDepth (AccountGroup *grp)
|
|
{
|
|
int i, depth=0, maxdepth=0;
|
|
if (!grp) return 0;
|
|
|
|
for (i=0; i<grp->numAcc; i++) {
|
|
depth = xaccGroupGetDepth (grp->account[i]->children);
|
|
if (depth > maxdepth) maxdepth = depth;
|
|
}
|
|
|
|
maxdepth++;
|
|
return maxdepth;
|
|
}
|
|
|
|
/********************************************************************\
|
|
\********************************************************************/
|
|
|
|
void
|
|
xaccGroupBeginStagedTransactionTraversals (AccountGroup *grp)
|
|
{
|
|
unsigned int numAcc;
|
|
unsigned int i;
|
|
|
|
if (!grp) return;
|
|
|
|
numAcc = grp->numAcc;
|
|
for(i = 0; i < numAcc; i++) {
|
|
unsigned int n = 0;
|
|
Account *acc;
|
|
Split *s = NULL;
|
|
acc = xaccGroupGetAccount(grp, i);
|
|
|
|
if(!acc) return;
|
|
|
|
/* recursively do sub-accounts */
|
|
xaccGroupBeginStagedTransactionTraversals(acc->children);
|
|
|
|
s = acc->splits[0];
|
|
while (s) {
|
|
Transaction *trans = s->parent;
|
|
trans->marker = 0;
|
|
n++;
|
|
s = acc->splits[n];
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
xaccAccountStagedTransactionTraversal (Account *acc,
|
|
unsigned int stage,
|
|
int (*callback)(Transaction *t, void *cb_data),
|
|
void *cb_data)
|
|
{
|
|
unsigned int n = 0;
|
|
Split *s = NULL;
|
|
|
|
if(!acc) return 0;
|
|
|
|
s = acc->splits[0];
|
|
if (callback) {
|
|
int retval;
|
|
while (s) {
|
|
Transaction *trans = s->parent;
|
|
if (trans && (trans->marker < stage)) {
|
|
trans->marker = stage;
|
|
retval = callback(trans, cb_data);
|
|
if (retval) return retval;
|
|
}
|
|
n++;
|
|
s = acc->splits[n];
|
|
}
|
|
} else {
|
|
while (s) {
|
|
Transaction *trans = s->parent;
|
|
if (trans && (trans->marker < stage)) {
|
|
trans->marker = stage;
|
|
}
|
|
n++;
|
|
s = acc->splits[n];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
xaccGroupStagedTransactionTraversal(AccountGroup *grp,
|
|
unsigned int stage,
|
|
int (*callback)(Transaction *t, void *cb_data),
|
|
void *cb_data)
|
|
{
|
|
unsigned int numAcc;
|
|
unsigned int i;
|
|
|
|
if (!grp) return 0;
|
|
|
|
numAcc = grp->numAcc;
|
|
for(i = 0; i < numAcc; i++) {
|
|
int retval;
|
|
int n = 0;
|
|
Account *acc;
|
|
acc = xaccGroupGetAccount(grp, i);
|
|
|
|
/* recursively do sub-accounts */
|
|
retval = xaccGroupStagedTransactionTraversal
|
|
(acc->children, stage, callback, cb_data);
|
|
if (retval) return retval;
|
|
retval = xaccAccountStagedTransactionTraversal (acc, stage, callback, cb_data);
|
|
if (retval) return retval;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/****************** END OF FILE *************************************/
|