From b41a03321719c720d9ea2475c076c3793010d6d5 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Sun, 20 Dec 1998 08:32:01 +0000 Subject: [PATCH] switch over to 64-bit timekeeping git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@1455 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/engine/FileIO.c | 90 +++++++++++++++++++++++++++------------ src/engine/Query.c | 18 +++----- src/engine/Transaction.c | 22 ++++++---- src/engine/Transaction.h | 28 +++++++++--- src/engine/TransactionP.h | 7 --- 5 files changed, 105 insertions(+), 60 deletions(-) diff --git a/src/engine/FileIO.c b/src/engine/FileIO.c index 127cbd0c69..dcace452aa 100644 --- a/src/engine/FileIO.c +++ b/src/engine/FileIO.c @@ -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 @@ -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) { - return -1; + long int sicks; + err = read( fd, &sicks, sizeof(long int) ); + if( err != sizeof(long int) ) + { + return -1; + } + 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); } - XACC_FLIP_INT (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; diff --git a/src/engine/Query.c b/src/engine/Query.c index 1bf615c9b6..202d8452f6 100644 --- a/src/engine/Query.c +++ b/src/engine/Query.c @@ -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; diff --git a/src/engine/Transaction.c b/src/engine/Transaction.c index 6f02eb34b5..e4682187fe 100644 --- a/src/engine/Transaction.c +++ b/src/engine/Transaction.c @@ -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 @@ -1443,7 +1446,7 @@ xaccTransSetDateSecs (Transaction *trans, time_t secs) if (!trans) return; CHECK_OPEN (trans); PINFO ("xaccTransSetDateSecs(): addr=%p set date to %lu %s \n", - trans, secs, ctime (&secs)); + trans, secs, ctime (&secs)); trans->date_posted.tv_sec = secs; trans->date_posted.tv_nsec = 0; @@ -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); diff --git a/src/engine/Transaction.h b/src/engine/Transaction.h index ff53ccf2d3..a70190acad 100644 --- a/src/engine/Transaction.h +++ b/src/engine/Transaction.h @@ -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 *); /* diff --git a/src/engine/TransactionP.h b/src/engine/TransactionP.h index 223493d2aa..a4b8bc13aa 100644 --- a/src/engine/TransactionP.h +++ b/src/engine/TransactionP.h @@ -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