conversion of FileIO to use splits

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@388 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 1998-01-07 07:23:31 +00:00
parent 934ed5efa3
commit 612dad2706
3 changed files with 414 additions and 204 deletions

View File

@ -37,6 +37,8 @@
* * * *
* Version 4 of the file format adds account groups * * Version 4 of the file format adds account groups *
* * * *
* Version 5 of the file format adds splits *
* *
* * * *
* the format of the data in the file: * * the format of the data in the file: *
* file ::== token Group * * file ::== token Group *
@ -44,9 +46,10 @@
* Account ::== accID flags type accountName description * * Account ::== accID flags type accountName description *
* notes numTran (Transaction)^numTrans * * notes numTran (Transaction)^numTrans *
* numGroups (Group)^numGroups * * numGroups (Group)^numGroups *
* Transaction ::== num date description memo catagory reconciled * * Transaction ::== num date description credit_split *
* amount share_price * * numSplits (Split)^numSplits *
* credit_account debit_account * * Split ::== memo action reconciled *
* amount share_price account *
* token ::== int [the version of file format == VERSION] * * token ::== int [the version of file format == VERSION] *
* numTrans ::== int * * numTrans ::== int *
* numAccounts ::== int * * numAccounts ::== int *
@ -62,12 +65,10 @@
* description ::== String * * description ::== String *
* memo ::== String * * memo ::== String *
* action ::== String * * action ::== String *
* catagory ::== int (obsolete) *
* reconciled ::== char * * reconciled ::== char *
* amount ::== double * * amount ::== double *
* share_price ::== double * * share_price ::== double *
* credit_account ::= int * * account ::= int *
* debit_account ::= int *
* String ::== size (char)^size * * String ::== size (char)^size *
* size ::== int * * size ::== int *
* Date ::== year month day * * Date ::== year month day *
@ -107,12 +108,14 @@ static Account *springAccount (int acc_id);
static AccountGroup *readGroup( int fd, Account *, int token ); static AccountGroup *readGroup( int fd, Account *, int token );
static Account *readAccount( int fd, AccountGroup *, int token ); static Account *readAccount( int fd, AccountGroup *, int token );
static Transaction *readTransaction( int fd, Account *, int token ); static Transaction *readTransaction( int fd, Account *, int token );
static Split *readSplit( int fd, int token );
static char *readString( int fd, int token ); static char *readString( int fd, int token );
static Date *readDate( int fd, int token ); static Date *readDate( int fd, int token );
static int writeGroup( int fd, AccountGroup *grp ); static int writeGroup( int fd, AccountGroup *grp );
static int writeAccount( int fd, Account *account ); static int writeAccount( int fd, Account *account );
static int writeTransaction( int fd, Transaction *trans ); static int writeTransaction( int fd, Transaction *trans );
static int writeSplit( int fd, Split *split);
static int writeString( int fd, char *str ); static int writeString( int fd, char *str );
static int writeDate( int fd, Date *date ); static int writeDate( int fd, Date *date );
@ -481,17 +484,18 @@ readTransaction( int fd, Account *acc, int token )
{ {
int err=0; int err=0;
int acc_id; int acc_id;
int i;
Date *date; Date *date;
int dummy_category; int dummy_category;
int numSplits;
Transaction *trans = 0x0; Transaction *trans = 0x0;
Split *split;
char *tmp; char *tmp;
char recn; char recn;
double num_shares = 0.0;
double share_price = 0.0;
/* create a transaction structure with at least one split */ /* create a transaction structure */
trans = mallocTransaction(); trans = mallocTransaction();
split = xaccMallocSplit();
xaccAppendSplit (trans, split);
ENTER ("readTransaction"); ENTER ("readTransaction");
@ -521,6 +525,11 @@ readTransaction( int fd, Account *acc, int token )
return NULL; return NULL;
} }
/* At version 5, most of the transaction stuff was
* moved to splits. Thus, vast majority of stuff below
* is skipped
*/
if (4 >= token) {
tmp = readString( fd, token ); tmp = readString( fd, token );
if( NULL == tmp ) if( NULL == tmp )
{ {
@ -533,13 +542,14 @@ readTransaction( int fd, Account *acc, int token )
/* action first introduced in version 3 of the file format */ /* action first introduced in version 3 of the file format */
if (3 <= token) { if (3 <= token) {
trans->action = readString( fd, token ); tmp = readString( fd, token );
if( trans->action == NULL ) if( tmp == NULL )
{ {
PERR ("Premature end of Transaction at memo"); PERR ("Premature end of Transaction at action");
freeTransaction(trans); freeTransaction(trans);
return NULL; return NULL;
} }
xaccTransSetAction (trans, tmp);
} }
/* category is now obsolete */ /* category is now obsolete */
@ -576,6 +586,7 @@ readTransaction( int fd, Account *acc, int token )
* YREC are defined to be... this way it might loose all * YREC are defined to be... this way it might loose all
* the reconciled data, but at least the field is valid */ * the reconciled data, but at least the field is valid */
if( (YREC != trans->credit_split.reconciled) && if( (YREC != trans->credit_split.reconciled) &&
(FREC != trans->credit_split.reconciled) &&
(CREC != trans->credit_split.reconciled) ) { (CREC != trans->credit_split.reconciled) ) {
xaccTransSetReconcile (trans, NREC); xaccTransSetReconcile (trans, NREC);
} }
@ -594,7 +605,8 @@ readTransaction( int fd, Account *acc, int token )
return NULL; return NULL;
} }
XACC_FLIP_INT (amount); XACC_FLIP_INT (amount);
split->damount = 0.01 * ((double) amount); /* file stores pennies */ num_shares = 0.01 * ((double) amount); /* file stores pennies */
trans->credit_split.damount = num_shares;
} else { } else {
double damount; double damount;
@ -607,7 +619,8 @@ readTransaction( int fd, Account *acc, int token )
return NULL; return NULL;
} }
XACC_FLIP_DOUBLE (damount); XACC_FLIP_DOUBLE (damount);
split->damount = damount; num_shares = damount;
trans->credit_split.damount = num_shares;
/* ... next read the share price ... */ /* ... next read the share price ... */
err = read( fd, &damount, sizeof(double) ); err = read( fd, &damount, sizeof(double) );
@ -618,10 +631,11 @@ readTransaction( int fd, Account *acc, int token )
return NULL; return NULL;
} }
XACC_FLIP_DOUBLE (damount); XACC_FLIP_DOUBLE (damount);
split->share_price = damount; share_price = damount;
trans->credit_split.share_price = share_price;
} }
INFO_2 ("readTransaction(): amount %f \n", trans->damount); INFO_2 ("readTransaction(): num_shares %f \n", num_shares);
/* Read the account numbers for double-entry */ /* Read the account numbers for double-entry */
/* These are first used in Version 2 of the file format */ /* These are first used in Version 2 of the file format */
@ -640,9 +654,9 @@ readTransaction( int fd, Account *acc, int token )
peer_acc = locateAccount (acc_id); peer_acc = locateAccount (acc_id);
trans -> credit_split.acc = (struct _account *) peer_acc; trans -> credit_split.acc = (struct _account *) peer_acc;
/* insert the transaction into both the debit and /* insert the split part of the transaction into
* the credit accounts; first the credit ... */ * the credited account */
if (peer_acc) insertTransaction( peer_acc, trans ); if (peer_acc) xaccInsertSplit( peer_acc, &(trans->credit_split) );
/* next read the debit account number */ /* next read the debit account number */
err = read( fd, &acc_id, sizeof(int) ); err = read( fd, &acc_id, sizeof(int) );
@ -655,20 +669,167 @@ readTransaction( int fd, Account *acc, int token )
XACC_FLIP_INT (acc_id); XACC_FLIP_INT (acc_id);
INFO_2 ("readTransaction(): debit %d\n", acc_id); INFO_2 ("readTransaction(): debit %d\n", acc_id);
peer_acc = locateAccount (acc_id); peer_acc = locateAccount (acc_id);
if (peer_acc) {
Split *split;
split = xaccMallocSplit ();
xaccAppendSplit (trans, split);
split -> acc = (struct _account *) peer_acc; split -> acc = (struct _account *) peer_acc;
xaccInsertSplit (peer_acc, split);
split->damount = -num_shares;
split->share_price = share_price;
}
/* insert the transaction into both the debit and
* the credit accounts; next, the debit ... */
if (peer_acc) insertTransaction( peer_acc, trans );
} else { } else {
/* Version 1 files did not do double-entry */ /* Version 1 files did not do double-entry */
insertTransaction( acc, trans ); xaccInsertSplit( acc, &(trans->credit_split) );
}
} else { /* else, read version-5 files */
Split *split;
/* first, read the credit split, and copy it in place */
split = readSplit (fd, token);
xaccSplitSetMemo ( &(trans->credit_split), split->memo);
xaccSplitSetAction ( &(trans->credit_split), split->action);
xaccSplitSetReconcile ( &(trans->credit_split), split->reconciled);
trans->credit_split.damount = split->damount;
trans->credit_split.share_price = split->share_price;
trans->credit_split.acc = split->acc;
trans->credit_split.parent = trans;
/* then wire it into place */
xaccInsertSplit( ((Account *) (trans->credit_split.acc)), &(trans->credit_split) );
/* free the thing that the read returned */
split->acc = NULL;
split->parent = NULL;
xaccFreeSplit (split);
/* read number of splits */
err = read( fd, &(numSplits), sizeof(int) );
if( err != sizeof(int) )
{
PERR ("Premature end of Transaction at num-splits");
freeTransaction(trans);
return NULL;
}
XACC_FLIP_INT (numSplits);
for (i=0; i<numSplits; i++) {
split = readSplit (fd, token);
split->parent = trans;
xaccAppendSplit( trans, split);
xaccInsertSplit( ((Account *) (split->acc)), split);
}
} }
return trans; return trans;
} }
/********************************************************************\
* readSplit *
* reads in the data for a split from the datafile *
* *
* Args: fd - the filedescriptor of the data file *
* token - the datafile version *
* Return: the transaction structure *
\********************************************************************/
static Split *
readSplit ( int fd, int token )
{
Account *peer_acc;
Split *split;
int err=0;
int acc_id;
char *tmp;
char recn;
double damount;
/* create a split structure */
split = xaccMallocSplit();
ENTER ("readSplit");
tmp = readString( fd, token );
if( NULL == tmp )
{
PERR ("Premature end of Split at memo");
xaccFreeSplit(split);
return NULL;
}
xaccSplitSetMemo (split, tmp);
XtFree (tmp);
tmp = readString( fd, token );
if( tmp == NULL )
{
PERR ("Premature end of Split at action");
xaccFreeSplit (split);
return NULL;
}
xaccSplitSetAction (split, tmp);
err = read( fd, &recn, sizeof(char) );
if( err != sizeof(char) )
{
PERR ("Premature end of Split at reconciled");
xaccFreeSplit (split);
return NULL;
}
xaccSplitSetReconcile (split, recn);
/* make sure the value of split->reconciled is valid...
* Do this mainly in case we change what NREC and
* YREC are defined to be... this way it might loose all
* the reconciled data, but at least the field is valid */
if( (YREC != split->reconciled) &&
(FREC != split->reconciled) &&
(CREC != split->reconciled) ) {
xaccSplitSetReconcile (split, NREC);
}
/* first, read number of shares ... */
err = read( fd, &damount, sizeof(double) );
if( err != sizeof(double) )
{
PERR ("Premature end of Split at amount");
xaccFreeSplit (split);
return NULL;
}
XACC_FLIP_DOUBLE (damount);
split -> damount = damount;
/* ... next read the share price ... */
err = read( fd, &damount, sizeof(double) );
if( err != sizeof(double) )
{
PERR ("Premature end of Split at share_price");
xaccFreeSplit (split);
return NULL;
}
XACC_FLIP_DOUBLE (damount);
split->share_price = damount;
INFO_2 ("readSplit(): num_shares %f \n", damount);
/* Read the account number */
err = read( fd, &acc_id, sizeof(int) );
if( err != sizeof(int) )
{
PERR ("Premature end of Split at account");
xaccFreeSplit (split);
return NULL;
}
XACC_FLIP_INT (acc_id);
INFO_2 ("readSplit(): account id %d\n", acc_id);
peer_acc = locateAccount (acc_id);
split -> acc = (struct _account *) peer_acc;
return split;
}
/********************************************************************\ /********************************************************************\
* readString * * readString *
* reads in a string (char *) from the datafile * * reads in a string (char *) from the datafile *
@ -775,7 +936,9 @@ xaccResetWriteFlags (AccountGroup *grp)
s = acc->splits[0]; s = acc->splits[0];
n=0; n=0;
while (s) { while (s) {
s -> write_flag = 0; Transaction *trans;
trans = s->parent;
if (trans) trans -> write_flag = 0;
n++; n++;
s = acc->splits[n]; s = acc->splits[n];
} }
@ -880,6 +1043,7 @@ static int
writeAccount( int fd, Account *acc ) writeAccount( int fd, Account *acc )
{ {
Transaction *trans; Transaction *trans;
Split *s;
int err=0; int err=0;
int i, numUnwrittenTrans, ntrans; int i, numUnwrittenTrans, ntrans;
int acc_id; int acc_id;
@ -918,11 +1082,22 @@ writeAccount( int fd, Account *acc )
/* figure out numTrans -- it will be less than the total /* figure out numTrans -- it will be less than the total
* number of transactions in this account, because some * number of transactions in this account, because some
* of the double entry transactions will already have been * of the double entry transactions will already have been
* written. */ * written. write_flag values are:
* 0 == uncounted, unwritten
* 1 == counted, unwritten
* 2 == written
*/
numUnwrittenTrans = 0; numUnwrittenTrans = 0;
for( i=0; i<acc->numTrans; i++ ) { i=0;
trans = getTransaction(acc,i); s = acc->splits[i];
if (0 == trans->credit_split.write_flag) numUnwrittenTrans ++; while (s) {
trans = s->parent;
if (0 == trans->write_flag) {
numUnwrittenTrans ++;
trans->write_flag = 1;
}
i++;
s = acc->splits[i];
} }
ntrans = numUnwrittenTrans; ntrans = numUnwrittenTrans;
@ -932,13 +1107,17 @@ writeAccount( int fd, Account *acc )
return -1; return -1;
INFO_2 ("writeAccount(): will write %d trans\n", numUnwrittenTrans); INFO_2 ("writeAccount(): will write %d trans\n", numUnwrittenTrans);
for( i=0; i<acc->numTrans; i++ ) { i=0;
trans = getTransaction(acc,i); s = acc->splits[i];
if (0 == trans->credit_split.write_flag) { while (s) {
trans = s->parent;
if (1 == trans->write_flag) {
err = writeTransaction( fd, trans ); err = writeTransaction( fd, trans );
}
if (-1 == err) return err; if (-1 == err) return err;
} }
i++;
s = acc->splits[i];
}
if (acc->children) { if (acc->children) {
numChildren = 1; numChildren = 1;
@ -948,8 +1127,7 @@ writeAccount( int fd, Account *acc )
XACC_FLIP_INT (numChildren); XACC_FLIP_INT (numChildren);
err = write( fd, &numChildren, sizeof(int) ); err = write( fd, &numChildren, sizeof(int) );
if( err != sizeof(int) ) if( err != sizeof(int) ) return -1;
return -1;
if (acc->children) { if (acc->children) {
err = writeGroup (fd, acc->children); err = writeGroup (fd, acc->children);
@ -963,84 +1141,108 @@ writeAccount( int fd, Account *acc )
* saves the data for a transaction to the datafile * * saves the data for a transaction to the datafile *
* * * *
* Args: fd - the filedescriptor of the data file * * Args: fd - the filedescriptor of the data file *
* acc - the account that the trans came from *
* trans - the transaction data to save * * trans - the transaction data to save *
* Return: -1 on failure * * Return: -1 on failure *
\********************************************************************/ \********************************************************************/
static int static int
writeTransaction( int fd, Transaction *trans ) writeTransaction( int fd, Transaction *trans )
{ {
Split *s;
int err=0; int err=0;
int tmp, acc_id; int i=0;
double damount;
Account *xfer_acc;
ENTER ("writeTransaction"); ENTER ("writeTransaction");
/* If we've already written this transaction, don't write /* If we've already written this transaction, don't write
* it again. That is, prevent double-entry transactions * it again. That is, prevent double-entry transactions
* from being written twice * from being written twice
*/ */
if (trans->credit_split.write_flag) return 4; if (2 == trans->write_flag) return 4;
trans->credit_split.write_flag = 1; trans->write_flag = 2;
err = writeString( fd, trans->num ); err = writeString( fd, trans->num );
if( -1 == err ) if( -1 == err ) return err;
return err;
err = writeDate( fd, &(trans->date) ); err = writeDate( fd, &(trans->date) );
if( -1 == err ) if( -1 == err ) return err;
return err;
err = writeString( fd, trans->description ); err = writeString( fd, trans->description );
if( -1 == err ) return err;
err = writeSplit( fd, &(trans->credit_split) );
if( -1 == err ) return err;
/* count the number of splits */
i = 0;
s = trans->debit_splits[i];
while (s) {
i++;
s = trans->debit_splits[i];
}
XACC_FLIP_INT (i);
err = write( fd, &i, sizeof(int) );
if( err != sizeof(int) ) return -1;
/* now write the splits */
i = 0;
s = trans->debit_splits[i];
while (s) {
err = writeSplit (fd, s);
if( -1 == err ) return err;
i++;
s = trans->debit_splits[i];
}
return err;
}
/********************************************************************\
* writeSplit *
* saves the data for a split to the datafile *
* *
* Args: fd - the filedescriptor of the data file *
* split - the split data to save *
* Return: -1 on failure *
\********************************************************************/
static int
writeSplit ( int fd, Split *split )
{
int err=0;
int tmp, acc_id;
double damount;
Account *xfer_acc;
ENTER ("writeSplit");
err = writeString( fd, split->memo );
if( -1 == err ) if( -1 == err )
return err; return err;
err = writeString( fd, trans->credit_split.memo ); err = writeString( fd, split->action );
if( -1 == err ) if( -1 == err )
return err; return err;
err = writeString( fd, trans->action ); err = write( fd, &(split->reconciled), sizeof(char) );
if( -1 == err )
return err;
/* category is now obsolete */
tmp = 0;
XACC_FLIP_INT (tmp);
err = write( fd, &tmp, sizeof(int) );
if( err != sizeof(int) )
return -1;
err = write( fd, &(trans->credit_split.reconciled), sizeof(char) );
if( err != sizeof(char) ) if( err != sizeof(char) )
return -1; return -1;
damount = trans->damount; damount = split->damount;
INFO_2 ("writeTransaction: amount=%f \n", damount); INFO_2 ("writeSplit: amount=%f \n", damount);
XACC_FLIP_DOUBLE (damount); XACC_FLIP_DOUBLE (damount);
err = write( fd, &damount, sizeof(double) ); err = write( fd, &damount, sizeof(double) );
if( err != sizeof(double) ) if( err != sizeof(double) )
return -1; return -1;
damount = trans->share_price; damount = split->share_price;
XACC_FLIP_DOUBLE (damount); XACC_FLIP_DOUBLE (damount);
err = write( fd, &damount, sizeof(double) ); err = write( fd, &damount, sizeof(double) );
if( err != sizeof(double) ) if( err != sizeof(double) )
return -1; return -1;
/* write the double-entry values */ /* write the credited/debted account */
xfer_acc = (Account *) (trans->credit_split.acc); xfer_acc = (Account *) (split->acc);
acc_id = -1; acc_id = -1;
if (xfer_acc) acc_id = xfer_acc -> id; if (xfer_acc) acc_id = xfer_acc -> id;
INFO_2 ("writeTransaction: credit %d \n", acc_id); INFO_2 ("writeSplit: credit %d \n", acc_id);
XACC_FLIP_INT (acc_id);
err = write( fd, &acc_id, sizeof(int) );
if( err != sizeof(int) )
return -1;
xfer_acc = (Account *) (trans->debit);
acc_id = -1;
if (xfer_acc) acc_id = xfer_acc -> id;
INFO_2 (" writeTransaction: debit %d \n", acc_id);
XACC_FLIP_INT (acc_id); XACC_FLIP_INT (acc_id);
err = write( fd, &acc_id, sizeof(int) ); err = write( fd, &acc_id, sizeof(int) );
if( err != sizeof(int) ) if( err != sizeof(int) )

View File

@ -1421,9 +1421,8 @@ regSaveTransaction( RegWindow *regData, int position )
String actn = NULL; String actn = NULL;
DEBUG("MOD_ACTN\n"); DEBUG("MOD_ACTN\n");
/* ... the action ... */ /* ... the action ... */
XtFree( trans->action );
actn = XbaeMatrixGetCell(regData->reg,row+ACTN_CELL_R,ACTN_CELL_C); actn = XbaeMatrixGetCell(regData->reg,row+ACTN_CELL_R,ACTN_CELL_C);
trans->action = XtNewString( actn ); xaccTransSetAction (trans, actn);
} }
if( regData->changed & MOD_RECN ) if( regData->changed & MOD_RECN )

View File

@ -164,24 +164,14 @@ initTransaction( Transaction * trans )
{ {
/* fill in some sane defaults */ /* fill in some sane defaults */
trans->debit = 0x0;
trans->num = XtNewString(""); trans->num = XtNewString("");
trans->description = XtNewString(""); trans->description = XtNewString("");
trans->action = XtNewString("");
trans->debit_splits = (Split **) _malloc (sizeof (Split *)); trans->debit_splits = (Split **) _malloc (sizeof (Split *));
trans->debit_splits[0] = NULL; trans->debit_splits[0] = NULL;
xaccInitSplit ( &(trans->credit_split)); xaccInitSplit ( &(trans->credit_split));
trans->credit_split->parent = trans;
trans->damount = 0.0;
trans->share_price = 1.0;
trans->credit_balance = 0.0;
trans->credit_cleared_balance = 0.0;
trans->debit_balance = 0.0;
trans->debit_cleared_balance = 0.0;
trans->date.year = 1900; trans->date.year = 1900;
trans->date.month = 1; trans->date.month = 1;
@ -219,19 +209,10 @@ implemented and tested.
_free (trans->debit_splits); _free (trans->debit_splits);
XtFree(trans->num); XtFree(trans->num);
XtFree(trans->description); XtFree(trans->description);
XtFree(trans->action);
/* just in case someone looks up freed memory ... */ /* just in case someone looks up freed memory ... */
trans->num = 0x0; trans->num = 0x0;
trans->description = 0x0; trans->description = 0x0;
trans->action = 0x0;
trans->damount = 0.0;
trans->share_price = 1.0;
trans->credit_balance = 0.0;
trans->credit_cleared_balance = 0.0;
trans->debit_balance = 0.0;
trans->debit_cleared_balance = 0.0;
trans->date.year = 1900; trans->date.year = 1900;
trans->date.month = 1; trans->date.month = 1;
@ -461,7 +442,6 @@ xaccTransSetDescription (Transaction *trans, char *desc)
trans->description = XtNewString (desc); trans->description = XtNewString (desc);
} }
void void
xaccTransSetMemo (Transaction *trans, char *memo) xaccTransSetMemo (Transaction *trans, char *memo)
{ {
@ -469,12 +449,41 @@ xaccTransSetMemo (Transaction *trans, char *memo)
trans->credit_split.memo = XtNewString (memo); trans->credit_split.memo = XtNewString (memo);
} }
void
xaccTransSetAction (Transaction *trans, char *actn)
{
if (trans->credit_split.action) XtFree (trans->credit_split.action);
trans->credit_split.action = XtNewString (actn);
}
void void
xaccTransSetReconcile (Transaction *trans, char recn) xaccTransSetReconcile (Transaction *trans, char recn)
{ {
trans->credit_split.reconciled = recn; trans->credit_split.reconciled = recn;
} }
/********************************************************************\
\********************************************************************/
void
xaccSplitSetMemo (Split *split, char *memo)
{
if (split->memo) XtFree (split->memo);
split->memo = XtNewString (memo);
}
void
xaccSplitSetAction (Split *split, char *actn)
{
if (split->action) XtFree (split->action);
split->action = XtNewString (actn);
}
void
xaccSplitSetReconcile (Split *split, char recn)
{
split->reconciled = recn;
}
/************************ END OF ************************************\ /************************ END OF ************************************\
\************************* FILE *************************************/ \************************* FILE *************************************/