diff --git a/src/SplitLedger.c b/src/SplitLedger.c index e295fc43ef..713bc6e442 100644 --- a/src/SplitLedger.c +++ b/src/SplitLedger.c @@ -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; diff --git a/src/engine/Account.c b/src/engine/Account.c index f66738cd0b..caf827488f 100644 --- a/src/engine/Account.c +++ b/src/engine/Account.c @@ -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); } } diff --git a/src/engine/AccountP.h b/src/engine/AccountP.h index 823c57effb..7c09c8486b 100644 --- a/src/engine/AccountP.h +++ b/src/engine/AccountP.h @@ -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. diff --git a/src/engine/Backend.c b/src/engine/Backend.c index d7ac715c39..8840ca8290 100644 --- a/src/engine/Backend.c +++ b/src/engine/Backend.c @@ -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); } /********************************************************************\ diff --git a/src/engine/TransLog.c b/src/engine/TransLog.c index ad715d1c35..72c8e7915e 100644 --- a/src/engine/TransLog.c +++ b/src/engine/TransLog.c @@ -22,12 +22,12 @@ \********************************************************************/ #define _GNU_SOURCE +#include "config.h" + #include #include #include -#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); diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c index c24d248472..640824bf0f 100644 --- a/src/engine/Transaction.c +++ b/src/engine/Transaction.c @@ -23,14 +23,14 @@ * * \********************************************************************/ +#include "config.h" + #include #include #include #include #include -#include "config.h" - #include "Account.h" #include "AccountP.h" #include "BackendP.h" @@ -300,13 +300,13 @@ 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,61 +896,62 @@ 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; - gnc_numeric value; - - s = sarray[0]; - value = gnc_numeric_zero(); + GList *node; + gnc_numeric value; - while (s) { - if (s != skip_me) { - /* 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. - * Well, that's ok, we'll just go with the flow. - */ - if (!(s->acc)) { - if (force_double_entry) { - assert (s->acc); - } - else { - value = gnc_numeric_add(value, s->value, GNC_DENOM_AUTO, - GNC_DENOM_LCD); - } - } - else if ((0x0 == base_currency) && (0 == force_double_entry)) { - value = gnc_numeric_add(value, s->value, GNC_DENOM_AUTO, - GNC_DENOM_LCD); - } - else { - /* OK, we've got a parent account, we've got currency, - * lets behave like professionals now, instead of the - * shenanigans above. - */ - if (gnc_commodity_equiv(s->acc->currency, base_currency)) { - value = gnc_numeric_add_fixed(value, s->value); - } - else if (gnc_commodity_equiv(s->acc->security, base_currency)) { - value = gnc_numeric_add_fixed(value, s->damount); - } - else { - PERR ("inconsistent currencies\n"); - printf("base = '%s', curr='%s', sec='%s'\n", - gnc_commodity_get_printname(base_currency), - gnc_commodity_get_printname(s->acc->currency), - gnc_commodity_get_printname(s->acc->security)); - assert (0); - } - } - } - i++; s = sarray [i]; - } + value = gnc_numeric_zero(); - return value; + 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. + * Well, that's ok, we'll just go with the flow. + */ + if (!(s->acc)) { + if (force_double_entry) { + assert (s->acc); + } + else { + value = gnc_numeric_add(value, s->value, GNC_DENOM_AUTO, + GNC_DENOM_LCD); + } + } + else if ((0x0 == base_currency) && (0 == force_double_entry)) { + value = gnc_numeric_add(value, s->value, GNC_DENOM_AUTO, + GNC_DENOM_LCD); + } + else { + /* OK, we've got a parent account, we've got currency, + * lets behave like professionals now, instead of the + * shenanigans above. + */ + if (gnc_commodity_equiv(s->acc->currency, base_currency)) { + value = gnc_numeric_add_fixed(value, s->value); + } + else if (gnc_commodity_equiv(s->acc->security, base_currency)) { + value = gnc_numeric_add_fixed(value, s->damount); + } + else { + PERR ("inconsistent currencies\n"); + printf("base = '%s', curr='%s', sec='%s'\n", + gnc_commodity_get_printname(base_currency), + gnc_commodity_get_printname(s->acc->currency), + gnc_commodity_get_printname(s->acc->security)); + assert (0); + } + } + } + + return value; } double @@ -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; - - if (!slist) return NULL; - - i = 0; - s = slist[0]; +FindCommonExclSCurrency (GList *splits, const gnc_commodity * ra, + const gnc_commodity * rb, Split *excl_split) +{ + GList *node; - /* 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]; - } + if (!splits) return NULL; - 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; @@ -1071,7 +1044,7 @@ FindCommonExclSCurrency (Split **slist, const gnc_commodity * ra, if ( aa && bb && ab && ba ) { ra = NULL; rb = NULL; } if (!ra) { ra = rb; rb = NULL; } - } + } else if (ra && !rb) { int aa = !gnc_commodity_equiv(ra,sa); @@ -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; @@ -1162,7 +1131,7 @@ xaccSplitRebalance (Split *split) /* We might have gotten here if someone is manipulating * a split that has not yet been inserted in a transaction. * Rather than punishing them with an assert, lets just - * quietly return. + * quietly return. */ if (!trans) return; @@ -1174,8 +1143,8 @@ 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. */ ra = split->acc->currency; @@ -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,47 +1165,49 @@ 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); /* what do we do if the value is different in the denominator * than the one for the account? */ - + /* KLUDGE -- bg */ xaccSplitSetBaseValue (s, gnc_numeric_neg(value), 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, * in which case we force a balancing split * to be created. */ - + if (force_double_entry) { if (! gnc_numeric_zero_p(split->damount)) { s = xaccMallocSplit (); @@ -1254,20 +1227,21 @@ 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 */ xaccSplitSetBaseValue (s, gnc_numeric_neg(value), @@ -1275,14 +1249,13 @@ xaccSplitRebalance (Split *split) MARK_SPLIT (s); xaccAccountRecomputeBalance (s->acc); } - + /* hack alert -- if the "force-double-entry" flag is set, * we should check to make sure that every split belongs * to some account. If any of them don't, force them * 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,19 +1335,20 @@ 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 - * value (i.e. is only recording a price). Otherwise, a single + * 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 * a matching opposite and place it either here (if force==1), * 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); - xaccSplitSetMemo (s, split->memo); + xaccSplitSetMemo (s, split->memo); xaccSplitSetAction (s, split->action); xaccSplitSetShareAmount(s, gnc_numeric_neg(split->damount)); xaccSplitSetValue(s, gnc_numeric_neg(split->value)); @@ -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,79 +1441,91 @@ 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; } HONKY_CAT (action); HONKY_CAT (memo); - + s->reconciled = so->reconciled; s->damount = so->damount; s->value = so->value; - + s->date_reconciled.tv_sec = so->date_reconciled.tv_sec; s->date_reconciled.tv_nsec = so->date_reconciled.tv_nsec; - + /* do NOT check date order until all of the other fields * have been properly restored */ 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; } } - + /* OK, if force_it got set, we'll have to tough it out and brute-force * the rest of the way. Clobber all the edited splits, add all new splits. * Unfortunately, this can suck up CPU cycles in the Remove/Insert routines. */ if (force_it) { - i=0; s = trans->splits[i]; - while (s && (isplits[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; isplits)[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 * @@ -2092,11 +1976,11 @@ xaccTransGetDateEnteredTS (Transaction *trans, Timespec *ts) *ts = (trans->date_entered); } -int +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) { - acc = s->acc; - if (acc) break; - i++; - s = trans->splits[i]; + for (node = trans->splits; node; node = node->next) + { + Split *s = node->data; + + acc = s->acc; + if (acc) break; } - 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) { - acc = s->acc; - if (acc) break; - i++; - s = trans->splits[i]; + for (node = trans->splits; node; node = node->next) + { + Split *s = node->data; + + acc = s->acc; + if (acc) break; } 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) { - Transaction *trans; + Split *s1, *s2; + Transaction *trans; - if (!split) return NULL; - trans = split->parent; + 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 *************************************/ diff --git a/src/engine/Transaction.h b/src/engine/Transaction.h index 969545bae9..5f82f4114e 100644 --- a/src/engine/Transaction.h +++ b/src/engine/Transaction.h @@ -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__ */ diff --git a/src/engine/TransactionP.h b/src/engine/TransactionP.h index b01604d34a..e9f24bbc5a 100644 --- a/src/engine/TransactionP.h +++ b/src/engine/TransactionP.h @@ -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. @@ -224,7 +216,7 @@ void xaccTransRemoveSplit (Transaction*, Split *); * (the share price of the source split is not changed). * If the indicated split is the source split, then the value * of the very first destination split is adjusted so that - * the balance is zero. If there is not destination split, + * the balance is zero. If there is not destination split, * one of two outcomes are possible, depending on whether * "forced_double_entry" is enabled or disabled. * (1) if forced-double-entry is disabled, the fact that @@ -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__ */ diff --git a/src/engine/io-gncbin-r.c b/src/engine/io-gncbin-r.c index 6932da4871..9a8ffcbc59 100644 --- a/src/engine/io-gncbin-r.c +++ b/src/engine/io-gncbin-r.c @@ -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; isplits->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); } } } diff --git a/src/engine/io-gncxml-r.c b/src/engine/io-gncxml-r.c index 562aa45ec3..259f142145 100644 --- a/src/engine/io-gncxml-r.c +++ b/src/engine/io-gncxml-r.c @@ -3344,22 +3344,11 @@ txn_restore_start_handler(GSList* sibling_data, gpointer *result, const gchar *tag) { Transaction *trans = xaccMallocTransaction(); - + if(!trans) return(FALSE); 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); diff --git a/src/gnome/dialog-transfer.c b/src/gnome/dialog-transfer.c index f37208971a..9bab67516e 100644 --- a/src/gnome/dialog-transfer.c +++ b/src/gnome/dialog-transfer.c @@ -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); diff --git a/src/scm/qif-import/qif-to-gnc.scm b/src/scm/qif-import/qif-to-gnc.scm index c37694ce0f..01b3f9b5e7 100644 --- a/src/scm/qif-import/qif-to-gnc.scm +++ b/src/scm/qif-import/qif-to-gnc.scm @@ -234,20 +234,11 @@ (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 qif-acct-map qif-cat-map) - + ;; rebalance and commit everything (gnc:transaction-commit-edit gnc-xtn))))) (qif-file:xtns qif-file)))