mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
rob generalizations of staged traversals & my fixes toi it
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@1714 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
@@ -1298,45 +1298,6 @@ readDMYDate( int fd, int token )
|
||||
********************** SAVE DATA ***********************************
|
||||
\********************************************************************/
|
||||
|
||||
static void
|
||||
xaccResetWriteFlags (AccountGroup *grp)
|
||||
{
|
||||
int i, numAcc;
|
||||
if (!grp) return;
|
||||
|
||||
/* Zero out the write flag on all of the
|
||||
* transactions. The write_flag is used to determine
|
||||
* if a given transaction has already been written
|
||||
* out to the file. This flag is necessary, since
|
||||
* double-entry transactions appear in two accounts,
|
||||
* while they should be written only once to the file.
|
||||
* The write_flag is used ONLY by the routines in this
|
||||
* module.
|
||||
*/
|
||||
numAcc = grp ->numAcc;
|
||||
for( i=0; i<numAcc; i++ ) {
|
||||
int n=0;
|
||||
Account *acc;
|
||||
Split *s = NULL;
|
||||
acc = xaccGroupGetAccount (grp,i) ;
|
||||
|
||||
/* recursively do sub-accounts */
|
||||
xaccResetWriteFlags (acc->children);
|
||||
|
||||
/* zip over all accounts */
|
||||
s = acc->splits[0];
|
||||
n=0;
|
||||
while (s) {
|
||||
Transaction *trans;
|
||||
trans = s->parent;
|
||||
if (trans) trans -> write_flag = 0;
|
||||
n++;
|
||||
s = acc->splits[n];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
* xaccWriteAccountGroupFile *
|
||||
* writes account date to two files: the current file, and a *
|
||||
@@ -1453,16 +1414,16 @@ xaccWriteAccountGroup (int fd, AccountGroup *grp )
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* OK, now zero out the write flag on all of the
|
||||
/* OK, now zero out the write flag on all of the
|
||||
* transactions. The write_flag is used to determine
|
||||
* if a given transaction has already been written
|
||||
* out to the file. This flag is necessary, since
|
||||
* if a given transaction has already been written
|
||||
* out to the file. This flag is necessary, since
|
||||
* double-entry transactions appear in two accounts,
|
||||
* while they should be written only once to the file.
|
||||
* The write_flag is used ONLY by the routines in this
|
||||
* module.
|
||||
*/
|
||||
xaccResetWriteFlags (grp);
|
||||
xaccGroupBeginStagedTransactionTraversals(grp);
|
||||
|
||||
for( i=0; i<grp->numAcc; i++ )
|
||||
{
|
||||
@@ -1517,6 +1478,21 @@ writeGroup (int fd, AccountGroup *grp )
|
||||
* acc - the account data to save *
|
||||
* Return: -1 on failure *
|
||||
\********************************************************************/
|
||||
|
||||
static int
|
||||
increment_int(Transaction *t, void *data)
|
||||
{
|
||||
int val = *((int *) data);
|
||||
*((int *) data) = val + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_write_transaction_wrapper_(Transaction *t, void *data)
|
||||
{
|
||||
return (-1 == writeTransaction(*((int *) data), t));
|
||||
}
|
||||
|
||||
static int
|
||||
writeAccount( int fd, Account *acc )
|
||||
{
|
||||
@@ -1602,23 +1578,17 @@ writeAccount( int fd, Account *acc )
|
||||
/* figure out numTrans -- it will be less than the total
|
||||
* number of transactions in this account, because some
|
||||
* of the double entry transactions will already have been
|
||||
* written. write_flag values are:
|
||||
* written.
|
||||
* marker flag values are:
|
||||
* 0 == uncounted, unwritten
|
||||
* 1 == counted, unwritten
|
||||
* 2 == written
|
||||
*/
|
||||
|
||||
/* Use a marker of 1 for counting numUnwrittenTrans */
|
||||
numUnwrittenTrans = 0;
|
||||
i=0;
|
||||
s = acc->splits[i];
|
||||
while (s) {
|
||||
trans = s->parent;
|
||||
if (0 == trans->write_flag) {
|
||||
numUnwrittenTrans ++;
|
||||
trans->write_flag = 1;
|
||||
}
|
||||
i++;
|
||||
s = acc->splits[i];
|
||||
}
|
||||
xaccAccountStagedTransactionTraversal(acc, 1,
|
||||
increment_int, &numUnwrittenTrans);
|
||||
|
||||
ntrans = numUnwrittenTrans;
|
||||
XACC_FLIP_INT (ntrans);
|
||||
@@ -1627,16 +1597,10 @@ writeAccount( int fd, Account *acc )
|
||||
return -1;
|
||||
|
||||
DEBUG ("writeAccount(): will write %d trans\n", numUnwrittenTrans);
|
||||
i=0;
|
||||
s = acc->splits[i];
|
||||
while (s) {
|
||||
trans = s->parent;
|
||||
if (1 == trans->write_flag) {
|
||||
err = writeTransaction( fd, trans );
|
||||
if (-1 == err) return err;
|
||||
}
|
||||
i++;
|
||||
s = acc->splits[i];
|
||||
|
||||
if(!xaccAccountStagedTransactionTraversal(acc, 2,
|
||||
_write_transaction_wrapper_, &fd)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (acc->children) {
|
||||
@@ -1673,12 +1637,6 @@ writeTransaction( int fd, Transaction *trans )
|
||||
Timespec ts;
|
||||
|
||||
ENTER ("writeTransaction");
|
||||
/* If we've already written this transaction, don't write
|
||||
* it again. That is, prevent double-entry transactions
|
||||
* from being written twice
|
||||
*/
|
||||
if (2 == trans->write_flag) return 4;
|
||||
trans->write_flag = 2;
|
||||
|
||||
err = writeString( fd, xaccTransGetNum (trans) );
|
||||
if( -1 == err ) return err;
|
||||
@@ -1892,14 +1850,4 @@ writeTSDate( int fd, Timespec *ts)
|
||||
return err;
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
/*
|
||||
Local Variables:
|
||||
tab-width: 2
|
||||
indent-tabs-mode: nil
|
||||
mode: c
|
||||
c-indentation-style: gnu
|
||||
eval: (c-set-offset 'block-open '-)
|
||||
End:
|
||||
*/
|
||||
/*********************** END OF FILE *********************************/
|
||||
|
||||
@@ -33,18 +33,11 @@
|
||||
#include "GroupP.h"
|
||||
#include "TransactionP.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#include "gnc-common.h"
|
||||
|
||||
/********************************************************************\
|
||||
* Because I can't use C++ for this project, doesn't mean that I *
|
||||
* can't pretend too! These functions perform actions on the *
|
||||
* 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. *
|
||||
\********************************************************************/
|
||||
@@ -54,7 +47,7 @@
|
||||
void
|
||||
xaccInitializeAccountGroup (AccountGroup *grp)
|
||||
{
|
||||
grp->saved = TRUE;
|
||||
grp->saved = GNC_T;
|
||||
|
||||
grp->parent = NULL;
|
||||
grp->numAcc = 0;
|
||||
@@ -96,7 +89,7 @@ xaccFreeAccountGroup( AccountGroup *grp )
|
||||
grp->numAcc = 0;
|
||||
grp->account = NULL;
|
||||
grp->balance = 0.0;
|
||||
|
||||
|
||||
_free(grp);
|
||||
}
|
||||
|
||||
@@ -108,7 +101,7 @@ xaccAccountGroupMarkSaved (AccountGroup *grp)
|
||||
int i;
|
||||
|
||||
if (!grp) return;
|
||||
grp->saved = TRUE;
|
||||
grp->saved = GNC_T;
|
||||
|
||||
for (i=0; i<grp->numAcc; i++) {
|
||||
xaccAccountGroupMarkSaved (grp->account[i]->children);
|
||||
@@ -124,7 +117,7 @@ xaccAccountGroupNotSaved (AccountGroup *grp)
|
||||
int i;
|
||||
|
||||
if (!grp) return 0;
|
||||
if (FALSE == grp->saved) return 1;
|
||||
if (GNC_F == grp->saved) return 1;
|
||||
|
||||
for (i=0; i<grp->numAcc; i++) {
|
||||
not_saved = xaccAccountGroupNotSaved (grp->account[i]->children);
|
||||
@@ -345,7 +338,7 @@ xaccRemoveGroup (AccountGroup *grp)
|
||||
grp = acc -> parent;
|
||||
if (!grp) return;
|
||||
|
||||
grp->saved = FALSE;
|
||||
grp->saved = GNC_F;
|
||||
}
|
||||
|
||||
/********************************************************************\
|
||||
@@ -378,7 +371,7 @@ xaccRemoveAccount (Account *acc)
|
||||
nacc --;
|
||||
arr[nacc] = NULL;
|
||||
grp->numAcc = nacc;
|
||||
grp->saved = FALSE;
|
||||
grp->saved = GNC_F;
|
||||
|
||||
/* if this was the last account in a group, delete
|
||||
* the group as well (unless its a root group) */
|
||||
@@ -432,7 +425,7 @@ xaccGroupInsertAccount( AccountGroup *grp, Account *acc )
|
||||
if (grp == acc->parent) ralo = 0;
|
||||
xaccRemoveAccount (acc);
|
||||
}
|
||||
grp->saved = FALSE;
|
||||
grp->saved = GNC_F;
|
||||
|
||||
/* set back-pointer to the accounts parent */
|
||||
acc->parent = grp;
|
||||
@@ -793,4 +786,103 @@ xaccGroupGetDepth (AccountGroup *grp)
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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 *************************************/
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#define __XACC_ACCOUNT_GROUP_H__
|
||||
|
||||
#include "config.h"
|
||||
#include "gnc-common.h"
|
||||
|
||||
#include "Account.h"
|
||||
|
||||
@@ -189,4 +190,85 @@ char * xaccAccountGetNextChildCode (Account *acc, int num_digits);
|
||||
void xaccGroupAutoCode (AccountGroup *grp, int num_digits);
|
||||
void xaccGroupDepthAutoCode (AccountGroup *grp);
|
||||
|
||||
#ifndef SWIG
|
||||
|
||||
/*
|
||||
* The following functions provide support for "staged traversals"
|
||||
* over all of the transactions in and account or group. The idea
|
||||
* is to be able to perform a sequence of traversals ("stages"),
|
||||
* and perform an operation on each transaction exactly once
|
||||
* for that stage.
|
||||
* Only transactions whose current "stage" is less than the
|
||||
* stage of the current traversal will be affected, and they will be
|
||||
* "brought up" to the current stage when they are processed.
|
||||
*
|
||||
* For example, you could perform a stage 1 traversal of all the
|
||||
* transactions in an account, and then perform a stage 1 traversal of
|
||||
* the transactions in a second account. Presuming the traversal of
|
||||
* the first account didn't abort prematurely, any transactions shared
|
||||
* by both accounts would be ignored during the traversal of the
|
||||
* second account since they had been processed while traversing the
|
||||
* first account.
|
||||
*
|
||||
* However, if you had traversed the second account using a stage
|
||||
* of 2, then all the transactions in the second account would have
|
||||
* been processed.
|
||||
*
|
||||
* Traversal can be aborted by having the callback function return a
|
||||
* non-zero value. The traversal is aborted immediately, and the
|
||||
* non-zero value is returned. Note that an aborted traversal can
|
||||
* be restarted; no information is lost due to an abort.
|
||||
*
|
||||
* The initial impetus for this particular approach came from
|
||||
* generalizing a mark/sweep practice that was already being used in
|
||||
* FileIO.c.
|
||||
*
|
||||
* Note that currently, there is a hard limit of 256 stages, which
|
||||
* can be changed by enlarging "marker" in the tranaction struct.
|
||||
* */
|
||||
|
||||
/* xaccGroupBeginStagedTransactionTraversals() resets the traversal
|
||||
* marker inside each of all the transactions in the group so that a
|
||||
* new sequence of staged traversals can begin.
|
||||
*/
|
||||
|
||||
void xaccGroupBeginStagedTransactionTraversals(AccountGroup *grp);
|
||||
|
||||
/* xaccGroupStagedTransactionTraversal() calls thunk on each
|
||||
* transaction in the group whose current marker is less than the
|
||||
* given `stage' and updates each transaction's marker to be `stage'.
|
||||
* The traversal will stop if thunk() returns a non-zero value.
|
||||
* xaccGroupStagedTransactionTraversal() function will return zero
|
||||
* or the non-zero value returned by thunk(). This
|
||||
* API does not handle handle recursive traversals.
|
||||
*
|
||||
* Currently the result of adding or removing transactions during a
|
||||
* traversal is undefined, so don't do that.
|
||||
*/
|
||||
|
||||
int
|
||||
xaccGroupStagedTransactionTraversal(AccountGroup *grp,
|
||||
unsigned int stage,
|
||||
int (*thunk)(Transaction *t, void *data),
|
||||
void *data);
|
||||
|
||||
/* xaccAccountStagedTransactionTraversal() calls thunk on each
|
||||
* transaction in the account whose current marker is less than the
|
||||
* given `stage' and updates each transaction's marker to be `stage'.
|
||||
* The traversal will stop if thunk() returns a non-zero value.
|
||||
* xaccAccountStagedTransactionTraversal() function will return zero
|
||||
* or the non-zero value returned by thunk().
|
||||
* This API does not handle handle recursive traversals.
|
||||
*
|
||||
* Currently the result of adding or removing transactions during a
|
||||
* traversal is undefined, so don't do that.
|
||||
*/
|
||||
|
||||
int xaccAccountStagedTransactionTraversal(Account *a,
|
||||
unsigned int stage,
|
||||
int (*thunk)(Transaction *t, void *data),
|
||||
void *data);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __XACC_ACCOUNT_GROUP_H__ */
|
||||
|
||||
@@ -343,7 +343,7 @@ xaccInitTransaction( Transaction * trans )
|
||||
trans->date_posted.tv_sec = 0;
|
||||
trans->date_posted.tv_nsec = 0;
|
||||
|
||||
trans->write_flag = 0;
|
||||
trans->marker = 0;
|
||||
trans->open = 0;
|
||||
trans->orig = NULL;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,13 @@ struct _transaction
|
||||
|
||||
Split **splits; /* list of splits, null terminated */
|
||||
|
||||
char write_flag; /* used only during file IO */
|
||||
/* marker is used to track the progress of transaction traversals.
|
||||
* 0 is never a legitimate marker value, so we can tell is we hit a
|
||||
* new transaction in the middle of a traversal. All each new
|
||||
* traversal cares about is whether or not the marker stored in a
|
||||
* transaction is the same as or different than the one
|
||||
* corresponding to the current traversal. */
|
||||
unsigned char marker;
|
||||
|
||||
/* the "open" flag indicates if the transaction has been
|
||||
* opened for editing. */
|
||||
|
||||
Reference in New Issue
Block a user