Use GLists to store splits in transactions. Remove cruft.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3120 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Dave Peticolas 2000-11-04 01:05:41 +00:00
parent 134940aab9
commit 4f84ccd735
12 changed files with 396 additions and 529 deletions

View File

@ -3230,9 +3230,10 @@ xaccSRLoadRegister (SplitRegister *reg, Split **slist,
xaccTransBeginEdit (trans, TRUE);
xaccTransSetDateSecs (trans, info->last_date_entered);
blank_split = xaccMallocSplit ();
xaccTransAppendSplit (trans, blank_split);
xaccTransCommitEdit (trans);
blank_split = xaccTransGetSplit (trans, 0);
info->blank_split_guid = *xaccSplitGetGUID (blank_split);
info->blank_split_edited = FALSE;

View File

@ -664,30 +664,25 @@ xaccAccountFixSplitDateOrder (Account * acc, Split *split ) {
/********************************************************************\
* xaccCheckTransDateOrder *
* check this transaction to see if the date is in correct order *
* If it is not, reorder the transactions ... *
* If it is not, reorder the transactions. *
* This routine perfroms the check for both of the double-entry *
* transaction entries ... *
* transaction entries. *
* *
* Args: trans -- the transaction to check *
* Return: int -- non-zero if out of order *
\********************************************************************/
void
xaccTransFixSplitDateOrder (Transaction *trans )
xaccTransFixSplitDateOrder (Transaction *trans)
{
Account * acc;
Split *s;
int i = 0;
GList *node;
if (NULL == trans) return;
if (trans == NULL) return;
i=0;
s = trans->splits[0];
while (s) {
acc = (Account *) (s->acc);
xaccAccountFixSplitDateOrder (acc, s);
i++;
s = trans->splits[i];
for (node = trans->splits; node; node = node->next)
{
Split *s = node->data;
xaccAccountFixSplitDateOrder (s->acc, s);
}
}

View File

@ -114,7 +114,7 @@ struct _account {
gnc_numeric share_cleared_balance;
gnc_numeric share_reconciled_balance;
GList *splits; /* ptr to array of ptrs to splits */
GList *splits; /* list of split pointers */
/* The "changed" flag is used to invalidate cached values in this structure.
* Currently, the balances and the cost basis are cached.

View File

@ -64,21 +64,21 @@ xaccAccountGetBackend (Account * acc)
Backend *
xaccTransactionGetBackend (Transaction *trans)
{
Backend *be;
GList *node;
Split *s;
if (!trans) return NULL;
/* find an account */
s = trans->splits[0];
s = xaccTransGetSplit (trans, 0);
if (!s) return NULL;
/* I suppose it would be more 'technically correct' to make sure that
* all splits share teh same backend, and flag an error if they
* all splits share the same backend, and flag an error if they
* don't. However, at this point, it seems quite unlikely, so we'll
* just use teh first backend we find.
* just use the first backend we find.
*/
be = xaccAccountGetBackend (s->acc);
return be;
return xaccAccountGetBackend (s->acc);
}
/********************************************************************\

View File

@ -22,12 +22,12 @@
\********************************************************************/
#define _GNU_SOURCE
#include "config.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "Account.h"
#include "AccountP.h"
#include "DateUtils.h"
@ -189,8 +189,7 @@ xaccCloseLog (void)
void
xaccTransWriteLog (Transaction *trans, char flag)
{
Split *split;
int i = 0;
GList *node;
char *dnow, *dent, *dpost, *drecn;
if (!gen_logs) return;
@ -202,10 +201,13 @@ xaccTransWriteLog (Transaction *trans, char flag)
fprintf (trans_log, "===== START\n");
split = trans->splits[0];
while (split) {
for (node = trans->splits; node; node = node->next) {
Split *split = node->data;
char * accname = "";
if (split->acc) accname = split->acc->accountName;
if (split->acc)
accname = split->acc->accountName;
drecn = xaccDateUtilGetStamp (split->date_reconciled.tv_sec);
/* use tab-separated fields */
@ -229,9 +231,8 @@ xaccTransWriteLog (Transaction *trans, char flag)
drecn
);
free (drecn);
i++;
split = trans->splits[i];
}
fprintf (trans_log, "===== END\n");
free (dnow);
free (dent);

View File

@ -23,14 +23,14 @@
* *
\********************************************************************/
#include "config.h"
#include <assert.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include "config.h"
#include "Account.h"
#include "AccountP.h"
#include "BackendP.h"
@ -300,12 +300,12 @@ xaccConfigGetForceDoubleEntry (void)
static void
MarkChanged (Transaction *trans)
{
if (trans->splits) {
int i=0;
while (trans->splits[i]) {
MARK_SPLIT (trans->splits[i]);
i++;
}
GList *node;
for (node = trans->splits; node; node = node->next)
{
Split *s = node->data;
MARK_SPLIT (s);
}
}
@ -554,23 +554,13 @@ xaccSplitGetShareReconciledBalance (Split *s) {
\********************************************************************/
static void
xaccInitTransaction( Transaction * trans )
xaccInitTransaction (Transaction * trans)
{
Split *split;
/* Fill in some sane defaults */
trans->num = g_strdup("");
trans->description = g_strdup("");
trans->splits = g_malloc (3 * sizeof (Split *));
/* Create a single split only. As soon as the balance becomes
* non-zero, additional splits will get created.
*/
split = xaccMallocSplit ();
split->parent = trans;
trans->splits[0] = split;
trans->splits[1] = NULL;
trans->splits = NULL;
trans->date_entered.tv_sec = 0;
trans->date_entered.tv_nsec = 0;
@ -611,22 +601,16 @@ static Transaction *
xaccCloneTransaction (Transaction *t)
{
Transaction *trans;
int n;
GList *node;
trans = g_new(Transaction, 1);
trans->num = g_strdup(t->num);
trans->description = g_strdup(t->description);
n=0; while (t->splits[n]) n++;
trans->splits = g_malloc ((n+1)* sizeof (Split *));
n=0;
while (t->splits[n]) {
trans->splits[n] = xaccCloneSplit (t->splits[n]);
n++;
}
trans->splits[n] = NULL;
trans->splits = g_list_copy (t->splits);
for (node = trans->splits; node; node = node->next)
node->data = xaccCloneSplit (node->data);
trans->date_entered.tv_sec = t->date_entered.tv_sec;
trans->date_entered.tv_nsec = t->date_entered.tv_nsec;
@ -649,27 +633,19 @@ xaccCloneTransaction (Transaction *t)
\********************************************************************/
void
xaccFreeTransaction( Transaction *trans )
xaccFreeTransaction (Transaction *trans)
{
int i;
Split *s;
GList *node;
if (!trans) return;
ENTER ("addr=%p\n", trans);
/* free up the destination splits */
if (trans->splits) {
i = 0;
s = trans->splits[i];
while (s) {
xaccFreeSplit (s);
i++;
s = trans->splits[i];
}
}
g_free (trans->splits);
for (node = trans->splits; node; node = node->next)
xaccFreeSplit (node->data);
g_list_free (trans->splits);
trans->splits = NULL;
/* free up transaction strings */
g_free (trans->num);
@ -728,23 +704,25 @@ xaccTransEqual(const Transaction *ta, const Transaction *tb,
if(kvp_frame_compare(ta->kvp_data, tb->kvp_data) != 0) return FALSE;
if(check_splits) {
Split** sa = ta->splits;
Split** sb = tb->splits;
GList *sa = ta->splits;
GList *sb = tb->splits;
if(!sa && sb) return FALSE;
if(!sb && sa) return FALSE;
if(sa && sb) {
/* presume that the splits are in the same order */
while(*sa && *sb) {
if(!xaccSplitEqual(*sa, *sb, check_guids, FALSE)) return(FALSE);
sa++;
sb++;
while(sa && sb) {
if(!xaccSplitEqual(sa->data, sb->data, check_guids, FALSE))
return(FALSE);
sa = sa->next;
sb = sb->next;
}
if(*sa != NULL) return(FALSE);
if(*sb != NULL) return(FALSE);
if(sa != NULL) return(FALSE);
if(sb != NULL) return(FALSE);
}
}
return(TRUE);
}
@ -918,18 +896,21 @@ xaccSplitGetBaseValue (Split *s, const gnc_commodity * base_currency) {
\********************************************************************/
static gnc_numeric
ComputeValue (Split **sarray, Split * skip_me,
ComputeValue (GList *splits, Split * skip_me,
const gnc_commodity * base_currency)
{
Split *s;
int i=0;
GList *node;
gnc_numeric value;
s = sarray[0];
value = gnc_numeric_zero();
while (s) {
if (s != skip_me) {
for (node = splits; node; node = node->next)
{
Split *s = node->data;
if (s == skip_me)
continue;
/* ahh -- users may not want or use the double entry
* features of this engine. So, in particular, there
* may be the occasional split without a parent account.
@ -969,8 +950,6 @@ ComputeValue (Split **sarray, Split * skip_me,
}
}
}
i++; s = sarray [i];
}
return value;
}
@ -1020,36 +999,30 @@ xaccIsCommonCurrency(const gnc_commodity * currency_1,
}
static const gnc_commodity *
FindCommonExclSCurrency (Split **slist, const gnc_commodity * ra,
const gnc_commodity * rb, Split *excl_split) {
Split * s;
int i = 0;
FindCommonExclSCurrency (GList *splits, const gnc_commodity * ra,
const gnc_commodity * rb, Split *excl_split)
{
GList *node;
if (!slist) return NULL;
if (!splits) return NULL;
i = 0;
s = slist[0];
/* If s is to be excluded, go ahead in the list until one split is
not excluded or is NULL. */
while (s && (s == excl_split)) {
i++; s = slist[i];
}
while (s) {
for (node = splits; node; node = node->next)
{
Split *s = node->data;
const gnc_commodity * sa, * sb;
if (s == excl_split)
continue;
/* Novice/casual users may not want or use the double entry
* features of this engine. Because of this, there
* may be the occasional split without a parent account.
* Well, that's ok, we'll just go with the flow.
*/
if (force_double_entry) {
if (force_double_entry)
assert (s->acc);
} else
if (NULL == s->acc) {
i++; s=slist[i]; continue;
}
else if (s->acc == NULL)
continue;
sa = s->acc->currency;
sb = s->acc->security;
@ -1080,14 +1053,6 @@ FindCommonExclSCurrency (Split **slist, const gnc_commodity * ra,
}
if ((!ra) && (!rb)) return NULL;
i++;
s = slist[i];
/* If s is to be excluded, go ahead in the list until one split is
not excluded or is NULL. */
while (s && (s == excl_split))
{ i++; s = slist[i]; }
}
return (ra);
@ -1098,23 +1063,26 @@ FindCommonExclSCurrency (Split **slist, const gnc_commodity * ra,
* common currency.
*/
static const gnc_commodity *
FindCommonCurrency (Split **slist,
FindCommonCurrency (GList *splits,
const gnc_commodity * ra, const gnc_commodity * rb)
{
return FindCommonExclSCurrency(slist, ra, rb, NULL);
return FindCommonExclSCurrency(splits, ra, rb, NULL);
}
const gnc_commodity *
xaccTransFindCommonCurrency (Transaction *trans)
{
const gnc_commodity * ra, * rb;
Split *split;
if (trans->splits == NULL) return NULL;
if (trans->splits[0] == NULL) return NULL;
if (trans->splits[0]->acc == NULL) return NULL;
ra = trans->splits[0]->acc->currency;
rb = trans->splits[0]->acc->security;
split = trans->splits->data;
if (split->acc == NULL) return NULL;
ra = split->acc->currency;
rb = split->acc->security;
return FindCommonCurrency (trans->splits, ra, rb);
}
@ -1145,15 +1113,16 @@ xaccTransIsCommonExclSCurrency (Transaction *trans,
static void
xaccTransRebalance (Transaction * trans)
{
xaccSplitRebalance (trans->splits[0]);
if (!trans || !trans->splits)
return;
xaccSplitRebalance (trans->splits->data);
}
void
xaccSplitRebalance (Split *split)
{
Transaction *trans;
Split *s;
int i = 0;
gnc_numeric value;
const gnc_commodity * base_currency = NULL;
@ -1174,7 +1143,7 @@ xaccSplitRebalance (Split *split)
if(split->acc->editlevel > 0) return;
assert (trans->splits);
assert (trans->splits[0]);
assert (trans->splits->data);
/* lets find out if we are dealing with multiple currencies,
* and which one(s) all of the splits have in common. */
@ -1183,9 +1152,11 @@ xaccSplitRebalance (Split *split)
base_currency = FindCommonCurrency (trans->splits, ra, rb);
if (!base_currency) {
GList *node;
PERR ("no common split currencies\n");
s = trans->splits[0];
while (s) {
for (node = trans->splits; node; node = node->next) {
Split *s = node->data;
if (s->acc) {
PERR ("\taccount=%s currency=%s security=%s\n",
s->acc->accountName,
@ -1194,24 +1165,25 @@ xaccSplitRebalance (Split *split)
} else {
PERR ("\t*** No parent account *** \n");
}
i++; s = trans->splits[i];
}
assert (0);
return;
}
} else {
assert (trans->splits);
assert (trans->splits[0]);
assert (trans->splits->data);
}
if (split == trans->splits[0]) {
if (split == trans->splits->data) {
Split *s;
/* The indicated split is the source split.
* Pick a destination split (by default,
* the first destination split), and force
* the total on it.
*/
s = trans->splits[1];
s = g_list_nth_data (trans->splits, 1);
if (s) {
/* the new value of the destination split will be the result. */
value = ComputeValue (trans->splits, s, base_currency);
@ -1225,9 +1197,10 @@ xaccSplitRebalance (Split *split)
base_currency);
MARK_SPLIT (s);
xaccAccountRecomputeBalance (s->acc);
}
else {
Split *s;
/* There are no destination splits !!
* Either this is allowed, in which case
* we just blow it off, or its forbidden,
@ -1254,18 +1227,19 @@ xaccSplitRebalance (Split *split)
s->memo = g_strdup (split->memo);
s->action = g_strdup (split->action);
}
}
}
}
else {
Split *s;
/* The indicated split is a destination split.
* Compute grand total of all destination splits,
* and force the source split to balance.
*/
s = trans->splits[0];
s = trans->splits->data;
value = ComputeValue (trans->splits, s, base_currency);
/* KLUDGE -- bg */
@ -1282,7 +1256,6 @@ xaccSplitRebalance (Split *split)
* into the current account. If there's not current account,
* force them into a lost & found account */
/* hack alert -- implement the above */
}
/********************************************************************\
@ -1327,9 +1300,8 @@ xaccTransBeginEdit (Transaction *trans, gboolean defer)
void
xaccTransCommitEdit (Transaction *trans)
{
int i;
GList *node;
Split *split;
Account *acc;
Backend *be;
if (!trans) return;
@ -1341,8 +1313,7 @@ xaccTransCommitEdit (Transaction *trans)
* has no splits in it, in which case we delete the transaction and
* return.
*/
split = trans->splits[0];
if (!split || (trans->open & BEING_DESTROYED))
if (!trans->splits || (trans->open & BEING_DESTROYED))
{
PINFO ("delete trans at addr=%p\n", trans);
/* Make a log in the journal before destruction. */
@ -1352,6 +1323,8 @@ xaccTransCommitEdit (Transaction *trans)
return;
}
split = trans->splits->data;
/* try to get the sorting order lined up according to
* when the user typed things in. */
if (0 == trans->date_entered.tv_sec) {
@ -1362,7 +1335,7 @@ xaccTransCommitEdit (Transaction *trans)
}
/* Alternately the transaction may have only one split in
* it, in which case ... that's OK if and only if the split has no
* it, in which case that's OK if and only if the split has no
* value (i.e. is only recording a price). Otherwise, a single
* split with a value can't possibly balance, thus violating the
* rules of double-entry, and that's way bogus. So create
@ -1370,7 +1343,8 @@ xaccTransCommitEdit (Transaction *trans)
* or in some dummy account (if force==2).
*/
if ((1 == force_double_entry) &&
(NULL == trans->splits[1]) && (!gnc_numeric_zero_p(split->damount))) {
(NULL == g_list_nth(trans->splits, 1)) &&
(!gnc_numeric_zero_p(split->damount))) {
Split * s = xaccMallocSplit();
xaccTransAppendSplit (trans, s);
xaccAccountInsertSplit (split->acc, s);
@ -1407,23 +1381,15 @@ xaccTransCommitEdit (Transaction *trans)
/* ------------------------------------------------- */
/* Make sure all associated splits are in proper order
* in their accounts. */
i=0;
split = trans->splits[i];
while (split) {
acc = split ->acc;
xaccAccountFixSplitDateOrder(acc, trans->splits[i]);
i++;
split = trans->splits[i];
for (node = trans->splits; node; node = node->next) {
split = node->data;
xaccAccountFixSplitDateOrder(split->acc, split);
}
/* Recompute the account balances. */
i=0;
split = trans->splits[i];
while (split) {
acc = split->acc;
xaccAccountRecomputeBalance (acc);
i++;
split = trans->splits[i];
for (node = trans->splits; node; node = node->next) {
split = node->data;
xaccAccountRecomputeBalance (split->acc);
}
trans->open = 0;
@ -1441,9 +1407,8 @@ void
xaccTransRollbackEdit (Transaction *trans)
{
Transaction *orig;
Split *s, *so;
Account * acc;
int force_it=0, mismatch=0, i;
int force_it=0, mismatch=0;
int i;
if (!trans) return;
@ -1476,16 +1441,25 @@ xaccTransRollbackEdit (Transaction *trans)
* forcing will suck memory cycles. So instead we'll try the gentle
* approach first. Note that even in the gentle approach, the
* CheckDateOrder routine could be cpu-cyle brutal, so it maybe
* it could use some tuning ...
* it could use some tuning.
*/
if (trans->open & BEING_DESTROYED) {
force_it = 1;
mismatch = 0;
} else {
i=0;
s = trans->splits[0];
so = orig->splits[0];
while (s && so) {
}
else {
GList *node;
GList *node_orig;
Split *s, *so;
s = so = NULL;
for (i = 0, node = trans->splits, node_orig = orig->splits ;
node && node_orig ;
i++, node = node->next, node_orig = node_orig->next) {
s = node->data;
so = node_orig->data;
if (so->acc != s->acc) { force_it = 1; mismatch=i; break; }
#define HONKY_CAT(val) { g_free(s->val); s->val=so->val; so->val=NULL; }
@ -1505,10 +1479,8 @@ xaccTransRollbackEdit (Transaction *trans)
xaccAccountFixSplitDateOrder (s->acc, s);
MARK_SPLIT (s);
xaccAccountRecomputeBalance (s->acc);
i++;
s = trans->splits[i];
so = orig->splits[i];
}
if (so != s) { force_it = 1; mismatch=i; }
}
@ -1517,38 +1489,43 @@ xaccTransRollbackEdit (Transaction *trans)
* Unfortunately, this can suck up CPU cycles in the Remove/Insert routines.
*/
if (force_it) {
i=0; s = trans->splits[i];
while (s && (i<mismatch)) {
xaccFreeSplit (orig->splits[i]);
orig->splits[i] = s;
i++;
s = trans->splits[i];
GList *node;
for (i = 0, node = trans->splits ;
node && i < mismatch ;
i++, node = node->next) {
Split *s = node->data;
GList *node_orig;
node_orig = g_list_nth (orig->splits, i);
xaccFreeSplit (node_orig->data);
node_orig->data = s;
}
i=mismatch; s = trans->splits[i];
while (s) {
acc = s->acc;
for (node = g_list_nth (trans->splits, mismatch) ;
node ; node = node->next) {
Split *s = node->data;
MARK_SPLIT (s);
xaccAccountRemoveSplit (acc, s);
xaccAccountRecomputeBalance (acc);
xaccAccountRemoveSplit (s->acc, s);
xaccAccountRecomputeBalance (s->acc);
xaccRemoveEntity(&s->guid);
xaccFreeSplit (s);
i++;
s = trans->splits[i];
}
g_free (trans->splits);
g_list_free (trans->splits);
trans->splits = orig->splits;
orig->splits = NULL;
i=mismatch; s = trans->splits[i];
while (s) {
acc = s->acc;
for (node = g_list_nth (trans->splits, mismatch) ;
node ; node = node->next) {
Split *s = node->data;
MARK_SPLIT (s);
xaccStoreEntity(s, &s->guid, GNC_ID_SPLIT);
xaccAccountInsertSplit (acc, s);
xaccAccountRecomputeBalance (acc);
i++;
s = trans->splits[i];
xaccAccountInsertSplit (s->acc, s);
xaccAccountRecomputeBalance (s->acc);
}
}
@ -1575,46 +1552,58 @@ xaccTransIsOpen (Transaction *trans)
void
xaccTransDestroy (Transaction *trans)
{
int i;
Split *split;
Account *acc;
GList *node;
if (!trans) return;
CHECK_OPEN (trans);
trans->open |= BEING_DESTROYED;
xaccTransWriteLog (trans, 'D');
i=0;
split = trans->splits[i];
while (split) {
for (node = trans->splits; node; node = node->next) {
Split *split = node->data;
MARK_SPLIT (split);
acc = split ->acc;
xaccAccountRemoveSplit (acc, split);
xaccAccountRecomputeBalance (acc);
xaccAccountRemoveSplit (split->acc, split);
xaccAccountRecomputeBalance (split->acc);
xaccRemoveEntity(&split->guid);
xaccFreeSplit (split);
trans->splits[i] = NULL;
i++;
split = trans->splits[i];
node->data = NULL;
}
g_list_free (trans->splits);
trans->splits = NULL;
xaccRemoveEntity(&trans->guid);
/* the actual free is done with the commit call, else its rolled back */
/* xaccFreeTransaction (trans); don't do this here ... */
}
/********************************************************************\
* TransRemoveSplit is an engine private function and does not/should
* not cause any rebalancing to occur.
\********************************************************************/
static void
xaccTransRemoveSplit (Transaction *trans, Split *split)
{
if (trans == NULL)
return;
trans->splits = g_list_remove (trans->splits, split);
}
/********************************************************************\
\********************************************************************/
void
xaccSplitDestroy (Split *split)
{
Account *acc;
Transaction *trans;
int numsplits = 0;
int ismember = 0;
Split *s;
gboolean ismember = FALSE;
GList *node;
if (!split) return;
@ -1625,14 +1614,16 @@ xaccSplitDestroy (Split *split)
xaccRemoveEntity(&split->guid);
numsplits = 0;
s = trans->splits[0];
while (s) {
MARK_SPLIT(s);
if (s == split) ismember = 1;
numsplits ++;
s = trans->splits[numsplits];
for (node = trans->splits; node; node = node->next)
{
Split *s = node->data;
MARK_SPLIT(s); /* why??? */
if (s == split)
ismember = TRUE;
}
assert (ismember);
/* If the account has three or more splits,
@ -1646,14 +1637,12 @@ xaccSplitDestroy (Split *split)
*/
MARK_SPLIT (split);
xaccTransRemoveSplit (trans, split);
acc = split->acc;
xaccAccountRemoveSplit (acc, split);
xaccAccountRecomputeBalance (acc);
xaccAccountRemoveSplit (split->acc, split);
xaccAccountRecomputeBalance (split->acc);
xaccFreeSplit (split);
if (2 < numsplits) {
xaccSplitRebalance (trans->splits[0]);
}
if (g_list_length (trans->splits) > 1)
xaccTransRebalance (trans);
}
/********************************************************************\
@ -1662,8 +1651,6 @@ xaccSplitDestroy (Split *split)
void
xaccTransAppendSplit (Transaction *trans, Split *split)
{
int i, num;
Split **oldarray;
Transaction *oldtrans;
if (!trans) return;
@ -1674,54 +1661,17 @@ xaccTransAppendSplit (Transaction *trans, Split *split)
/* first, make sure that the split isn't already inserted
* elsewhere. If so, then remove it. */
oldtrans = split->parent;
if (oldtrans) {
if (oldtrans)
xaccTransRemoveSplit (oldtrans, split);
xaccTransRebalance (oldtrans);
}
/* now, insert the split into the array */
split->parent = trans;
num = xaccCountSplits (trans->splits);
oldarray = trans->splits;
trans->splits = (Split **) g_malloc ((num+2)*sizeof(Split *));
for (i=0; i<num; i++) {
(trans->splits)[i] = oldarray[i];
}
trans->splits[num] = split;
trans->splits[num+1] = NULL;
g_free (oldarray);
trans->splits = g_list_append (trans->splits, split);
/* force double entry to always be consistent */
xaccSplitRebalance (split);
}
/********************************************************************\
* TransRemoveSplit is an engine private function and does not/should
* not cause any rebalancing to occur.
\********************************************************************/
void
xaccTransRemoveSplit (Transaction *trans, Split *split)
{
int i=0, n=0;
Split *s;
if (!split) return;
if (!trans) return;
split->parent = NULL;
s = trans->splits[0];
while (s) {
trans->splits[i] = trans->splits[n];
if (split == s) { i--; }
i++;
n++;
s = trans->splits[n];
}
trans->splits[i] = NULL;
if (oldtrans && oldtrans != trans)
xaccTransRebalance (oldtrans);
}
/********************************************************************\
@ -1864,25 +1814,6 @@ xaccTransOrder (Transaction *ta, Transaction *tb)
/********************************************************************\
\********************************************************************/
int
xaccCountTransactions (Transaction **tarray)
{
Transaction *trans;
int ntrans = 0;
if (!tarray) return 0;
trans = tarray[0];
while (trans) {
ntrans ++;
trans = tarray[ntrans];
}
return ntrans;
}
/********************************************************************\
\********************************************************************/
void
xaccTransSetDateSecs (Transaction *trans, time_t secs)
{
@ -1991,50 +1922,6 @@ xaccTransSetDescription (Transaction *trans, const char *desc)
MarkChanged (trans);
}
#define SET_TRANS_FIELD(trans,field,value) \
{ \
char * tmp; \
if (!trans) return; \
CHECK_OPEN (trans); \
\
/* the engine *must* always be internally consistent */ \
assert (trans->splits); \
assert (trans->splits[0]); \
\
/* there must be two splits if value of one non-zero */ \
if (force_double_entry) { \
if (! gnc_numeric_zero_p(trans->splits[0]->damount)) { \
assert (trans->splits[1]); \
} \
} \
\
tmp = g_strdup (value); \
g_free (trans->splits[0]->field); \
trans->splits[0]->field = tmp; \
MARK_SPLIT (trans->splits[0]); \
\
/* If there are just two splits, then keep them in sync. */ \
if (NULL != trans->splits[1]) { \
if (NULL == trans->splits[2]) { \
g_free (trans->splits[1]->field); \
trans->splits[1]->field = g_strdup (tmp); \
MARK_SPLIT (trans->splits[1]); \
} \
} \
}
void
xaccTransSetMemo (Transaction *trans, const char *mimeo)
{
SET_TRANS_FIELD (trans, memo, mimeo);
}
void
xaccTransSetAction (Transaction *trans, const char *actn)
{
SET_TRANS_FIELD (trans, action, actn);
}
/********************************************************************\
\********************************************************************/
@ -2042,12 +1929,9 @@ Split *
xaccTransGetSplit (Transaction *trans, int i)
{
if (!trans) return NULL;
if (0 > i) return NULL;
/* hack alert - should check if i > sizeof array */
if (trans->splits) {
return (trans->splits[i]);
}
return NULL;
if (i < 0) return NULL;
return g_list_nth_data (trans->splits, i);
}
const char *
@ -2096,7 +1980,7 @@ int
xaccTransCountSplits (Transaction *trans)
{
if (!trans) return 0;
return (xaccCountSplits (trans->splits));
return g_list_length (trans->splits);
}
/********************************************************************\
@ -2256,28 +2140,25 @@ xaccSplitGetSharePrice (Split * split) {
Account *
xaccGetAccountByName (Transaction *trans, const char * name)
{
Split *s;
Account *acc = NULL;
int i;
GList *node;
if (!trans) return NULL;
if (!name) return NULL;
/* walk through the splits, looking for one, any one, that has a
* parent account */
i = 0;
s = trans->splits[0];
while (s) {
for (node = trans->splits; node; node = node->next)
{
Split *s = node->data;
acc = s->acc;
if (acc) break;
i++;
s = trans->splits[i];
}
if (!acc) return 0x0;
if (!acc) return NULL;
acc = xaccGetPeerAccountFromName (acc, name);
return acc;
return xaccGetPeerAccountFromName (acc, name);
}
/********************************************************************\
@ -2287,28 +2168,25 @@ Account *
xaccGetAccountByFullName (Transaction *trans, const char * name,
const char separator)
{
Split *s;
Account *acc = NULL;
int i;
GList *node;
if (!trans) return NULL;
if (!name) return NULL;
/* walk through the splits, looking for one, any one, that has a
* parent account */
i = 0;
s = trans->splits[0];
while (s) {
for (node = trans->splits; node; node = node->next)
{
Split *s = node->data;
acc = s->acc;
if (acc) break;
i++;
s = trans->splits[i];
}
if (!acc) return NULL;
acc = xaccGetPeerAccountFromFullName (acc, name, separator);
return acc;
return xaccGetPeerAccountFromFullName (acc, name, separator);
}
/********************************************************************\
@ -2317,17 +2195,22 @@ xaccGetAccountByFullName (Transaction *trans, const char * name,
Split *
xaccGetOtherSplit (Split *split)
{
Split *s1, *s2;
Transaction *trans;
if (!split) return NULL;
trans = split->parent;
/* if more than two splits, return NULL */
if ((trans->splits[1]) && (trans->splits[2])) return NULL;
if (g_list_length (trans->splits) != 2)
return NULL;
if (split == trans->splits[0]) return (trans->splits[1]);
if (split == trans->splits[1]) return (trans->splits[0]);
return NULL; /* never reached, in theory */
s1 = g_list_nth_data (trans->splits, 0);
s2 = g_list_nth_data (trans->splits, 1);
if (s1 == split)
return s2;
return s1;
}
/********************************************************************\
@ -2354,12 +2237,5 @@ IthSplit (Split **list, int i)
return list[i];
}
Transaction *
IthTransaction (Transaction **list, int i)
{
if (!list || 0 > i) return NULL;
return list[i];
}
/************************ END OF ************************************\
\************************* FILE *************************************/

View File

@ -172,16 +172,6 @@ void xaccTransSetDateEnteredTS (Transaction *trans,
void xaccTransSetNum (Transaction *trans, const char *num);
void xaccTransSetDescription (Transaction *trans, const char *desc);
/* The xaccTransSetMemo() and xaccTransSetAction() methods are
* convenience routines to keep the memo and action fields
* of two-split transactions in sync. If the transaction has
* precisely two splits, then these routines will set the memo
* and action of both splits. Otherwise, they will set the
* memo and action of the first split (source split) only.
*/
void xaccTransSetMemo (Transaction *trans, const char *memo);
void xaccTransSetAction (Transaction *trans, const char *action);
/* The xaccTransAppendSplit() method will append the indicated
* split to the collection of splits in this transaction.
* If the split is already a part of another transaction,
@ -473,10 +463,6 @@ int xaccSplitDateOrder (Split *sa, Split *sb);
/********************************************************************\
* Miscellaneous utility routines.
\********************************************************************/
/*
* count the number of transactions in the null-terminated array
*/
int xaccCountTransactions (Transaction **tarray);
/* count the number of splits in the indicated array */
int xaccCountSplits (Split **sarray);
@ -507,12 +493,11 @@ Split * xaccGetOtherSplit (Split *split);
*/
int xaccIsPeerSplit (Split *split_1, Split *split_2);
/* The IthSplit() and IthTransaction() routines merely dereference
* the lists supplied as arguments; i.e. they return list[i].
* These routines are needed by the perl swig wrappers, which
* are unable to dereference on their own.
/* The IthSplit() routine merely dereferences
* the list supplied as argument; i.e. it returns list[i].
* This routine is needed by the perl swig wrappers, which
* is unable to dereference on their own.
*/
Transaction * IthTransaction (Transaction **tarray, int i);
Split * IthSplit (Split **sarray, int i);
#endif /* __XACC_TRANSACTION_H__ */

View File

@ -100,9 +100,7 @@ struct _split
* it's NULL until accessed. */
kvp_frame * kvp_data;
/* The reconciled field ...
*/
char reconciled;
char reconciled; /* The reconciled field */
Timespec date_reconciled; /* date split was reconciled */
/* value is the amount of the account's currency involved,
@ -155,7 +153,7 @@ struct _transaction
* it's NULL until accessed. */
kvp_frame * kvp_data;
Split **splits; /* list of splits, null terminated */
GList *splits; /* list of splits */
/* marker is used to track the progress of transaction traversals.
* 0 is never a legitimate marker value, so we can tell is we hit
@ -192,7 +190,7 @@ void xaccSplitSetGUID (Split *split, GUID *guid);
* not check to see if any of the member splits are referenced
* by an account.
*/
void xaccFreeTransaction (Transaction *);
void xaccFreeTransaction (Transaction *trans);
/* The xaccFreeSplit() method simply frees all memory associated
* with the split. It does not verify that the split isn't
@ -200,13 +198,7 @@ void xaccFreeTransaction (Transaction *);
* account, then calling this method will leave the system in an
* inconsistent state.
*/
void xaccFreeSplit (Split *); /* frees memory */
/* The xaccTransRemoveSplit() routine will remove the indicated
* split from the transaction. It will *NOT* otherwise
* re-adjust balances, modify accounts, etc.
*/
void xaccTransRemoveSplit (Transaction*, Split *);
void xaccFreeSplit (Split *split); /* frees memory */
/*
@ -216,7 +208,7 @@ void xaccTransRemoveSplit (Transaction*, Split *);
* splits in a transaction to total up to exactly zero.
*
* It is worthwhile to understand the algorithm that this routine
* uses to acheive balance. It goes like this:
* uses to achieve balance. It goes like this:
* If the indicated split is a destination split (i.e. is not
* the first split), then the total value of the destination
* splits is computed, and the value of the source split (ie.
@ -236,12 +228,12 @@ void xaccTransRemoveSplit (Transaction*, Split *);
* destination split properly.
*/
void xaccSplitRebalance (Split *);
void xaccSplitRebalance (Split *split);
/* FIXME: this is probably wrong, but it'll have to wait until Bill
returns. It's *ONLY* for file IO. Don't use these elsewhere. */
void xaccSplitSetValueDirectly(Split *s, gnc_numeric n);
void xaccSplitSetQuantityDirectly(Split *s, gnc_numeric n);
void xaccSplitSetValueDirectly(Split *split, gnc_numeric value);
void xaccSplitSetQuantityDirectly(Split *split, gnc_numeric quantity);
#endif /* __XACC_TRANSACTION_P_H__ */

View File

@ -662,20 +662,6 @@ readAccount( int fd, AccountGroup *grp, int token )
"\texpected %d got %d transactions \n",numTrans,i);
break;
}
#ifdef DELINT_BLANK_SPLITS_HACK
/* This is dangerous, as it can destroy real data. */
{
int j=0;
Split *s = trans->splits[0];
while (s) {
if (DEQ(0.0,s->damount) && DEQ (1.0,s->share_price)) {
xaccTransRemoveSplit (trans, s);
break;
}
j++; s=trans->splits[j];
}
}
#endif /* DELINT_BLANK_SPLITS_HACK */
}
/* Not needed now. Since we always look in ids_to_finished_accounts
@ -780,6 +766,40 @@ readAccInfo(int fd, Account *acc, int token) {
return(TRUE);
}
static void
xaccTransSetMemo (Transaction *trans, const char *memo)
{
Split *s;
if (!trans || !memo) return;
s = xaccTransGetSplit (trans, 0);
xaccSplitSetMemo (s, memo);
if (xaccTransCountSplits (trans) != 2)
return;
s = xaccTransGetSplit (trans, 1);
xaccSplitSetMemo (s, memo);
}
static void
xaccTransSetAction (Transaction *trans, const char *action)
{
Split *s;
if (!trans || !action) return;
s = xaccTransGetSplit (trans, 0);
xaccSplitSetAction (s, action);
if (xaccTransCountSplits (trans) != 2)
return;
s = xaccTransGetSplit (trans, 1);
xaccSplitSetAction (s, action);
}
/********************************************************************\
* readTransaction *
* reads in the data for a transaction from the datafile *
@ -809,6 +829,12 @@ readTransaction( int fd, Account *acc, int token )
trans = xaccMallocTransaction();
xaccTransBeginEdit (trans, 1);
/* add in one split -- xaccMallocTransaction no longer auto-creates them. */
{
Split *s = xaccMallocSplit ();
xaccTransAppendSplit (trans, s);
}
tmp = readString( fd, token );
if (NULL == tmp)
{
@ -1084,14 +1110,16 @@ readTransaction( int fd, Account *acc, int token )
if (5 == token)
{
Split *s = trans->splits->data;
/* Version 5 files included a split that immediately
* followed the transaction, before the destination splits.
* Later versions don't have this. */
offset = 1;
split = readSplit (fd, token);
xaccRemoveEntity(&trans->splits[0]->guid);
xaccFreeSplit (trans->splits[0]);
trans->splits[0] = split;
xaccRemoveEntity(&s->guid);
xaccFreeSplit (s);
trans->splits->data = split;
split->parent = trans;
}
@ -1108,13 +1136,14 @@ readTransaction( int fd, Account *acc, int token )
for (i=0; i<numSplits; i++) {
split = readSplit (fd, token);
if (0 == i+offset) {
Split *s = trans->splits->data;
/* the first split has been malloced. just replace it */
xaccRemoveEntity (&trans->splits[i+offset]->guid);
xaccFreeSplit (trans->splits[i+offset]);
trans->splits[i+offset] = split;
xaccRemoveEntity (&s->guid);
xaccFreeSplit (s);
trans->splits->data = split;
split->parent = trans;
} else {
xaccTransAppendSplit( trans, split);
xaccTransAppendSplit(trans, split);
}
}
}

View File

@ -3349,17 +3349,6 @@ txn_restore_start_handler(GSList* sibling_data,
xaccTransBeginEdit(trans, 1);
/* Kill the pointless initial splits -- why are these here?
FIXME: Can we kill them in Transaction.c? */
{
int i = 0;
Split *useless;
while((useless = xaccTransGetSplit(trans, i))) {
xaccSplitDestroy(useless);
i++;
}
}
*data_for_children = trans;
return(TRUE);

View File

@ -726,9 +726,11 @@ gnc_xfer_dialog_ok_cb(GtkWidget * widget, gpointer data)
string = gtk_entry_get_text(GTK_ENTRY(xferData->description_entry));
xaccTransSetDescription(trans, string);
/* first split is already there */
curr_split = xaccTransGetSplit(trans, 0);
/* second split must be created */
/* create first split */
curr_split = xaccMallocSplit();
xaccTransAppendSplit(trans, curr_split);
/* create second split */
from_split = xaccMallocSplit();
xaccTransAppendSplit(trans, from_split);
@ -741,9 +743,10 @@ gnc_xfer_dialog_ok_cb(GtkWidget * widget, gpointer data)
DxaccSplitSetBaseValue(curr_split, amount, from_currency);
DxaccSplitSetBaseValue(curr_split, to_amount, to_currency);
/* TransSetMemo will set the memo for both splits */
/* Set the memo fields */
string = gtk_entry_get_text(GTK_ENTRY(xferData->memo_entry));
xaccTransSetMemo(trans, string);
xaccSplitSetMemo(curr_split, string);
xaccSplitSetMemo(from_split, string);
/* finish transaction */
xaccAccountCommitEdit(from);
@ -763,9 +766,11 @@ gnc_xfer_dialog_ok_cb(GtkWidget * widget, gpointer data)
string = gtk_entry_get_text(GTK_ENTRY(xferData->description_entry));
xaccTransSetDescription(trans, string);
/* first split is already there */
curr_split = xaccTransGetSplit(trans, 0);
/* second split must be created */
/* create first split */
curr_split = xaccMallocSplit();
xaccTransAppendSplit(trans, curr_split);
/* create second split */
to_split = xaccMallocSplit();
xaccTransAppendSplit(trans, to_split);
@ -778,9 +783,10 @@ gnc_xfer_dialog_ok_cb(GtkWidget * widget, gpointer data)
DxaccSplitSetBaseValue(curr_split, -amount, from_currency);
DxaccSplitSetBaseValue(curr_split, -to_amount, to_currency);
/* TransSetMemo will set the memo for both splits */
/* set the memo fields */
string = gtk_entry_get_text(GTK_ENTRY(xferData->memo_entry));
xaccTransSetMemo(trans, string);
xaccSplitSetMemo(curr_split, string);
xaccSplitSetMemo(to_split, string);
/* finish transaction */
xaccAccountCommitEdit(curr);
@ -806,18 +812,20 @@ gnc_xfer_dialog_ok_cb(GtkWidget * widget, gpointer data)
string = gtk_entry_get_text(GTK_ENTRY(xferData->description_entry));
xaccTransSetDescription(trans, string);
/* first split is already there */
to_split = xaccTransGetSplit(trans, 0);
/* create first split */
to_split = xaccMallocSplit();
xaccTransAppendSplit(trans, to_split);
DxaccSplitSetShareAmount(to_split, amount);
/* second split must be created */
/* create second split */
from_split = xaccMallocSplit();
DxaccSplitSetShareAmount(from_split, -amount);
xaccTransAppendSplit(trans, from_split);
/* TransSetMemo will set the memo for both splits */
/* set the memo fields */
string = gtk_entry_get_text(GTK_ENTRY(xferData->memo_entry));
xaccTransSetMemo(trans, string);
xaccSplitSetMemo(to_split, string);
xaccSplitSetMemo(from_split, string);
/* Now do the 'to' account */
xaccAccountBeginEdit(to);

View File

@ -234,15 +234,6 @@
(let ((gnc-xtn (gnc:transaction-create)))
(gnc:transaction-begin-edit gnc-xtn 1)
;; destroy any automagic splits in the transaction
(let ((numsplits (gnc:transaction-get-split-count gnc-xtn)))
(if (not (eqv? 0 numsplits))
(let splitloop ((ind (- numsplits 1)))
(gnc:split-destroy
(gnc:transaction-get-split gnc-xtn ind))
(if (> ind 0)
(loop (- ind 1))))))
;; build the transaction
(qif-import:qif-xtn-to-gnc-xtn
xtn qif-file gnc-xtn gnc-acct-hash