mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
switch over to 64-bit timekeeping
git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@1455 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
34580c58e3
commit
b41a033217
@ -84,8 +84,8 @@
|
||||
* String ::== size (char)^size *
|
||||
* size ::== int *
|
||||
* Date ::== seconds nanoseconds *
|
||||
* seconds ::== unsigned 32 bit int *
|
||||
* nanoseconds ::== unsigned 32 bit int *
|
||||
* seconds ::== signed 64 bit int *
|
||||
* nanoseconds ::== signed 32 bit int *
|
||||
\********************************************************************/
|
||||
|
||||
#include <fcntl.h>
|
||||
@ -110,7 +110,7 @@
|
||||
#define PERMS 0666
|
||||
#define WFLAGS (O_WRONLY | O_CREAT | O_TRUNC)
|
||||
#define RFLAGS O_RDONLY
|
||||
#define VERSION 8
|
||||
#define VERSION 9
|
||||
|
||||
|
||||
/* hack alert the current file format does not support most of the
|
||||
@ -146,7 +146,7 @@ static Transaction *readTransaction( int fd, Account *, int token );
|
||||
static Split *readSplit( int fd, int token );
|
||||
static char *readString( int fd, int token );
|
||||
static time_t readDMYDate( int fd, int token );
|
||||
static int readTSDate( int fd, struct timespec *, int token );
|
||||
static int readTSDate( int fd, Timespec *, int token );
|
||||
|
||||
static int writeAccountGroupToFile( char *datafile, AccountGroup *grp );
|
||||
static int writeGroup( int fd, AccountGroup *grp );
|
||||
@ -154,7 +154,7 @@ static int writeAccount( int fd, Account *account );
|
||||
static int writeTransaction( int fd, Transaction *trans );
|
||||
static int writeSplit( int fd, Split *split);
|
||||
static int writeString( int fd, char *str );
|
||||
static int writeTSDate( int fd, struct timespec *);
|
||||
static int writeTSDate( int fd, Timespec *);
|
||||
|
||||
/*******************************************************/
|
||||
/* backwards compatibility definitions for numeric value
|
||||
@ -230,15 +230,33 @@ double xaccFlipDouble (double val)
|
||||
return u.d;
|
||||
}
|
||||
|
||||
long long xaccFlipLongLong (long long val)
|
||||
{
|
||||
union {
|
||||
unsigned int i[2];
|
||||
long long d;
|
||||
} u;
|
||||
unsigned int w0, w1;
|
||||
u.d = val;
|
||||
w0 = xaccFlipInt (u.i[0]);
|
||||
w1 = xaccFlipInt (u.i[1]);
|
||||
|
||||
u.i[0] = w1;
|
||||
u.i[1] = w0;
|
||||
return u.d;
|
||||
}
|
||||
|
||||
/* if we are running on a little-endian system, we need to
|
||||
* do some endian flipping, because the xacc native data
|
||||
* format is big-endian */
|
||||
* format is big-endian. In particular, Intel x86 is little-endian. */
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
#define XACC_FLIP_DOUBLE(x) { (x) = xaccFlipDouble (x); }
|
||||
#define XACC_FLIP_LONG_LONG(x) { (x) = xaccFlipLongLong (x); }
|
||||
#define XACC_FLIP_INT(x) { (x) = xaccFlipInt (x); }
|
||||
#define XACC_FLIP_SHORT(x) { (x) = xaccFlipShort (x); }
|
||||
#else
|
||||
#define XACC_FLIP_DOUBLE(x)
|
||||
#define XACC_FLIP_LONG_LONG(x)
|
||||
#define XACC_FLIP_INT(x)
|
||||
#define XACC_FLIP_SHORT(x)
|
||||
#endif /* WORDS_BIGENDIAN */
|
||||
@ -673,7 +691,7 @@ readTransaction( int fd, Account *acc, int token )
|
||||
xaccTransSetDateSecs (trans, secs);
|
||||
xaccTransSetDateEnteredSecs (trans, secs);
|
||||
} else {
|
||||
struct timespec ts;
|
||||
Timespec ts;
|
||||
int rc;
|
||||
|
||||
/* read posted date first ... */
|
||||
@ -1011,9 +1029,9 @@ readSplit ( int fd, int token )
|
||||
}
|
||||
xaccSplitSetReconcile (split, recn);
|
||||
|
||||
/* version 8 and newwer files store date-reconciled */
|
||||
/* version 8 and newer files store date-reconciled */
|
||||
if (8 <= token) {
|
||||
struct timespec ts;
|
||||
Timespec ts;
|
||||
int rc;
|
||||
|
||||
rc = readTSDate( fd, &ts, token );
|
||||
@ -1124,20 +1142,37 @@ readString( int fd, int token )
|
||||
* Return: the Date struct *
|
||||
\********************************************************************/
|
||||
static int
|
||||
readTSDate( int fd, struct timespec *ts, int token )
|
||||
readTSDate( int fd, Timespec *ts, int token )
|
||||
{
|
||||
int err=0;
|
||||
unsigned int secs, nsecs;
|
||||
long long int secs = 0; /* 64-bit int */
|
||||
long int nsecs = 0;
|
||||
|
||||
err = read( fd, &secs, sizeof(unsigned int) );
|
||||
if( err != sizeof(unsigned int) )
|
||||
/* secs is a 32-bit in in version 8 & earlier files,
|
||||
* and goes 64-bit in the later files */
|
||||
if (8 >= token)
|
||||
{
|
||||
long int sicks;
|
||||
err = read( fd, &sicks, sizeof(long int) );
|
||||
if( err != sizeof(long int) )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
XACC_FLIP_INT (secs);
|
||||
XACC_FLIP_INT (sicks);
|
||||
secs = sicks;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = read( fd, &secs, sizeof(long long int) );
|
||||
if( err != sizeof(long long int) )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
XACC_FLIP_LONG_LONG (secs);
|
||||
}
|
||||
|
||||
err = read( fd, &nsecs, sizeof(unsigned int) );
|
||||
if( err != sizeof(unsigned int) )
|
||||
err = read( fd, &nsecs, sizeof(long int) );
|
||||
if( err != sizeof(long int) )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@ -1511,7 +1546,7 @@ writeTransaction( int fd, Transaction *trans )
|
||||
Split *s;
|
||||
int err=0;
|
||||
int i=0;
|
||||
struct timespec ts;
|
||||
Timespec ts;
|
||||
|
||||
ENTER ("writeTransaction");
|
||||
/* If we've already written this transaction, don't write
|
||||
@ -1570,7 +1605,7 @@ writeSplit ( int fd, Split *split )
|
||||
{
|
||||
int err=0;
|
||||
int acc_id;
|
||||
struct timespec ts;
|
||||
Timespec ts;
|
||||
double damount;
|
||||
Account *xfer_acc = NULL;
|
||||
char recn;
|
||||
@ -1663,21 +1698,22 @@ writeString( int fd, char *str )
|
||||
* Return: -1 on failure *
|
||||
\********************************************************************/
|
||||
static int
|
||||
writeTSDate( int fd, struct timespec *ts)
|
||||
writeTSDate( int fd, Timespec *ts)
|
||||
{
|
||||
int err=0;
|
||||
unsigned int tmp;
|
||||
int tmp;
|
||||
long long ltmp;
|
||||
|
||||
/* write 32 bits to file format, even if time_t is 64 bits */
|
||||
tmp = ts->tv_sec;
|
||||
XACC_FLIP_INT (tmp);
|
||||
err = write( fd, &tmp, sizeof(unsigned int) );
|
||||
if( err != sizeof(int) )
|
||||
/* write 64 bits to file format */
|
||||
ltmp = ts->tv_sec;
|
||||
XACC_FLIP_LONG_LONG (ltmp);
|
||||
err = write( fd, &tmp, sizeof(long long int) );
|
||||
if( err != sizeof(long long int) )
|
||||
return -1;
|
||||
|
||||
tmp = ts->tv_nsec;
|
||||
XACC_FLIP_INT (tmp);
|
||||
err = write( fd, &tmp, sizeof(unsigned int) );
|
||||
err = write( fd, &tmp, sizeof(int) );
|
||||
if( err != sizeof(int) )
|
||||
return -1;
|
||||
|
||||
|
@ -79,6 +79,8 @@ xaccMallocQuery (void)
|
||||
|
||||
static int Sort_DATE_NUM_AMOUNT (Split **, Split **);
|
||||
|
||||
#define LONG_LONG_MAX 0x7fffffffffffffffLL
|
||||
|
||||
void
|
||||
xaccInitQuery (Query *q)
|
||||
{
|
||||
@ -89,23 +91,17 @@ xaccInitQuery (Query *q)
|
||||
q->changed = 0;
|
||||
q->max_num_splits = INT_MAX ;
|
||||
|
||||
q->earliest.tv_sec = 0;
|
||||
q->earliest.tv_sec = - (LONG_LONG_MAX) - 1;
|
||||
q->earliest.tv_nsec = 0;
|
||||
|
||||
/* hack alert HACK ALERT Y2K problem -- danger danger.
|
||||
* For some stupid reason, struct Timespec uses long int
|
||||
* instead of time_t for seconds. This means we will have
|
||||
* overflow in year 2004 which is stupid, and needs to be
|
||||
* fixed.
|
||||
*/
|
||||
/* q->latest.tv_sec = ULONG_MAX; */
|
||||
q->latest.tv_sec = LONG_MAX;
|
||||
/* Its a signed, 64-bit int */
|
||||
q->latest.tv_sec = LONG_LONG_MAX;
|
||||
q->latest.tv_nsec = 0;
|
||||
|
||||
q->earliest_found.tv_sec = LONG_MAX;
|
||||
q->earliest_found.tv_sec = LONG_LONG_MAX;
|
||||
q->earliest_found.tv_nsec = 0;
|
||||
|
||||
q->latest_found.tv_sec = 0;
|
||||
q->latest_found.tv_sec = - (LONG_LONG_MAX) - 1;
|
||||
q->latest_found.tv_nsec = 0;
|
||||
|
||||
q->sort_func = (int (*)(const void*, const void *)) Sort_DATE_NUM_AMOUNT;
|
||||
|
@ -892,8 +892,11 @@ xaccTransCommitEdit (Transaction *trans)
|
||||
(trans->orig->date_posted.tv_sec != trans->date_posted.tv_sec))
|
||||
{
|
||||
|
||||
DEBUG ("xaccTransCommitEdit(): date changed to %lu %s\n",
|
||||
trans->date_posted.tv_sec, ctime (&trans->date_posted.tv_sec));
|
||||
DEBUGCMD ({
|
||||
time_t sicko = trans->date_posted.tv_sec;
|
||||
DEBUG ("xaccTransCommitEdit(): date changed to %Lu %s\n",
|
||||
trans->date_posted.tv_sec, ctime (&sicko));
|
||||
})
|
||||
/* since the date has changed, we need to be careful to
|
||||
* make sure all associated splits are in proper order
|
||||
* in thier accounts. The easiest way of ensuring this
|
||||
@ -1469,19 +1472,22 @@ xaccTransSetDateEnteredSecs (Transaction *trans, time_t secs)
|
||||
}
|
||||
|
||||
void
|
||||
xaccTransSetDateTS (Transaction *trans, struct timespec *ts)
|
||||
xaccTransSetDateTS (Transaction *trans, Timespec *ts)
|
||||
{
|
||||
if (!trans) return;
|
||||
CHECK_OPEN (trans);
|
||||
PINFO ("xaccTransSetDateTS(): addr=%p set date to %lu %s \n",
|
||||
trans, ts->tv_sec, ctime (&ts->tv_sec));
|
||||
DEBUGCMD ({
|
||||
time_t sicko = ts->tv_sec;
|
||||
PINFO ("xaccTransSetDateTS(): addr=%p set date to %Lu %s \n",
|
||||
trans, ts->tv_sec, ctime (&sicko));
|
||||
})
|
||||
|
||||
trans->date_posted.tv_sec = ts->tv_sec;
|
||||
trans->date_posted.tv_nsec = ts->tv_nsec;
|
||||
}
|
||||
|
||||
void
|
||||
xaccTransSetDateEnteredTS (Transaction *trans, struct timespec *ts)
|
||||
xaccTransSetDateEnteredTS (Transaction *trans, Timespec *ts)
|
||||
{
|
||||
if (!trans) return;
|
||||
CHECK_OPEN (trans);
|
||||
@ -1740,7 +1746,7 @@ xaccSplitSetDateReconciledSecs (Split *split, time_t secs)
|
||||
}
|
||||
|
||||
void
|
||||
xaccSplitSetDateReconciledTS (Split *split, struct timespec *ts)
|
||||
xaccSplitSetDateReconciledTS (Split *split, Timespec *ts)
|
||||
{
|
||||
if (!split) return;
|
||||
MARK_SPLIT (split);
|
||||
|
@ -54,6 +54,20 @@ typedef struct _account_group AccountGroup;
|
||||
typedef struct _split Split;
|
||||
typedef struct _transaction Transaction;
|
||||
|
||||
/* struct timespec64 is just like timespec except that we use
|
||||
* a 64-bit signed int to store the seconds. This should adequetely
|
||||
* cover dates in the distant future as well as the distant past, as long
|
||||
* as they're not more than a couple dozen times the age of the universe.
|
||||
* Note that both gcc and the IBM Toronto xlC compiler (aka CSet,
|
||||
* VisualAge, etc) correctly handle long long as a 64 bit quantity,
|
||||
* even on the 32-bit Intel x86 and PowerPC architectures. I'm assuming
|
||||
* that all the other modern compilers are clean on this issue too ...
|
||||
*/
|
||||
struct timespec64 {
|
||||
long long int tv_sec;
|
||||
long int tv_nsec;
|
||||
};
|
||||
typedef struct timespec64 Timespec;
|
||||
|
||||
/** PROTOTYPES ******************************************************/
|
||||
/*
|
||||
@ -115,7 +129,7 @@ void xaccTransRollbackEdit (Transaction *);
|
||||
* xaccTransSetDateSecs(), but takes a convenient day-month-year format.
|
||||
*
|
||||
* The xaccTransSetDateTS() method does the same thing as
|
||||
* xaccTransSetDateSecs(), but takes a struct timespec.
|
||||
* xaccTransSetDateSecs(), but takes a struct timespec64.
|
||||
*
|
||||
* The xaccTransSetDateToday() method does the same thing as
|
||||
* xaccTransSetDateSecs(), but sets the date to the current system
|
||||
@ -124,10 +138,10 @@ void xaccTransRollbackEdit (Transaction *);
|
||||
void xaccTransSetDate (Transaction *, int day, int mon, int year);
|
||||
void xaccTransSetDateSecs (Transaction *, time_t);
|
||||
void xaccTransSetDateToday (Transaction *);
|
||||
void xaccTransSetDateTS (Transaction *, struct timespec *);
|
||||
void xaccTransSetDateTS (Transaction *, Timespec *);
|
||||
|
||||
void xaccTransSetDateEnteredSecs (Transaction *, time_t);
|
||||
void xaccTransSetDateEnteredTS (Transaction *, struct timespec *);
|
||||
void xaccTransSetDateEnteredTS (Transaction *, Timespec *);
|
||||
|
||||
|
||||
/* set the Num and Description fields ... */
|
||||
@ -188,8 +202,8 @@ char * xaccTransGetNum (Transaction *);
|
||||
char * xaccTransGetDescription (Transaction *);
|
||||
char * xaccTransGetDocref (Transaction *);
|
||||
time_t xaccTransGetDate (Transaction *);
|
||||
void xaccTransGetDateTS (Transaction *, struct timespec *);
|
||||
void xaccTransGetDateEnteredTS (Transaction *, struct timespec *);
|
||||
void xaccTransGetDateTS (Transaction *, Timespec *);
|
||||
void xaccTransGetDateEnteredTS (Transaction *, Timespec *);
|
||||
|
||||
/* return the number of splits */
|
||||
int xaccTransCountSplits (Transaction *trans);
|
||||
@ -260,8 +274,8 @@ void xaccSplitSetDocref (Split *, const char *);
|
||||
*/
|
||||
void xaccSplitSetReconcile (Split *, char);
|
||||
void xaccSplitSetDateReconciledSecs (Split *, time_t);
|
||||
void xaccSplitSetDateReconciledTS (Split *, struct timespec *);
|
||||
void xaccSplitGetDateReconciledTS (Split *, struct timespec *);
|
||||
void xaccSplitSetDateReconciledTS (Split *, Timespec *);
|
||||
void xaccSplitGetDateReconciledTS (Split *, Timespec *);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -50,13 +50,6 @@
|
||||
#include "config.h"
|
||||
#include "Transaction.h" /* for typedefs */
|
||||
|
||||
/* Major-League Hack Alert -- bit Y2K problem: struct timespec seems
|
||||
* to have declared tv_sec to be a signed long, not an unsigned long.
|
||||
* This majorly hoses in the year 2004, as date comparisons suddenly
|
||||
* fail because the seconds value will go negative.
|
||||
*/
|
||||
typedef struct timespec Timespec;
|
||||
|
||||
/** STRUCTS *********************************************************/
|
||||
/*
|
||||
* Double-entry is forced by having at least two splits in every
|
||||
|
Loading…
Reference in New Issue
Block a user