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
zzzoldfeatures/xacc-12-patch
Linas Vepstas 27 years ago
parent 024944df2b
commit 5d0ee4210e

@ -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. */

Loading…
Cancel
Save