From 01af8148442c445859aa9a3cc97e7c95c948107f Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Fri, 23 May 2008 15:43:55 +0000 Subject: [PATCH] gmtime_r threadsafe. git-svn-id: file:///svn/unbound/trunk@1099 be551aaa-1e26-0410-a405-d3ace91eadb9 --- compat/gmtime_r.c | 116 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 4 deletions(-) diff --git a/compat/gmtime_r.c b/compat/gmtime_r.c index 2588ad85c..231d37e93 100644 --- a/compat/gmtime_r.c +++ b/compat/gmtime_r.c @@ -1,12 +1,120 @@ +/* + * Taken from FreeBSD src / lib / libc / stdtime / localtime.c 1.43 revision. + * localtime.c 7.78. + * tzfile.h 1.8 + * adapted to be replacement gmtime_r. + */ #include "config.h" #ifdef HAVE_TIME_H #include #endif -struct tm *gmtime_r(const time_t *timep, struct tm *result) +#define MONSPERYEAR 12 +#define DAYSPERNYEAR 365 +#define DAYSPERLYEAR 366 +#define SECSPERMIN 60 +#define SECSPERHOUR (60*60) +#define SECSPERDAY (24*60*60) +#define DAYSPERWEEK 7 +#define TM_SUNDAY 0 +#define TM_MONDAY 1 +#define TM_TUESDAY 2 +#define TM_WEDNESDAY 3 +#define TM_THURSDAY 4 +#define TM_FRIDAY 5 +#define TM_SATURDAY 6 + +#define TM_JANUARY 0 +#define TM_FEBRUARY 1 +#define TM_MARCH 2 +#define TM_APRIL 3 +#define TM_MAY 4 +#define TM_JUNE 5 +#define TM_JULY 6 +#define TM_AUGUST 7 +#define TM_SEPTEMBER 8 +#define TM_OCTOBER 9 +#define TM_NOVEMBER 10 +#define TM_DECEMBER 11 + +#define TM_YEAR_BASE 1900 + +#define EPOCH_YEAR 1970 +#define EPOCH_WDAY TM_THURSDAY + +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + +static const int mon_lengths[2][MONSPERYEAR] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +static const int year_lengths[2] = { + DAYSPERNYEAR, DAYSPERLYEAR +}; + +static void +timesub(timep, offset, tmp) +const time_t * const timep; +const long offset; +struct tm * const tmp; +{ + long days; + long rem; + long y; + int yleap; + const int * ip; + + days = *timep / SECSPERDAY; + rem = *timep % SECSPERDAY; + rem += (offset); + while (rem < 0) { + rem += SECSPERDAY; + --days; + } + while (rem >= SECSPERDAY) { + rem -= SECSPERDAY; + ++days; + } + tmp->tm_hour = (int) (rem / SECSPERHOUR); + rem = rem % SECSPERHOUR; + tmp->tm_min = (int) (rem / SECSPERMIN); + /* + ** A positive leap second requires a special + ** representation. This uses "... ??:59:60" et seq. + */ + tmp->tm_sec = (int) (rem % SECSPERMIN) ; + tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); + if (tmp->tm_wday < 0) + tmp->tm_wday += DAYSPERWEEK; + y = EPOCH_YEAR; +#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) + while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { + long newy; + + newy = y + days / DAYSPERNYEAR; + if (days < 0) + --newy; + days -= (newy - y) * DAYSPERNYEAR + + LEAPS_THRU_END_OF(newy - 1) - + LEAPS_THRU_END_OF(y - 1); + y = newy; + } + tmp->tm_year = y - TM_YEAR_BASE; + tmp->tm_yday = (int) days; + ip = mon_lengths[yleap]; + for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) + days = days - (long) ip[tmp->tm_mon]; + tmp->tm_mday = (int) (days + 1); + tmp->tm_isdst = 0; +} + +/* +* Re-entrant version of gmtime. +*/ +struct tm * gmtime_r(const time_t* timep, struct tm *tm) { - /* no thread safety. */ - *result = *gmtime(timep); - return result; + timesub(timep, 0L, tm); + return tm; } -- 2.47.2