diff options
Diffstat (limited to 'libc')
| -rw-r--r-- | libc/misc/time/time.c | 231 | 
1 files changed, 145 insertions, 86 deletions
| diff --git a/libc/misc/time/time.c b/libc/misc/time/time.c index 8176e071a..ac2fe5926 100644 --- a/libc/misc/time/time.c +++ b/libc/misc/time/time.c @@ -1,31 +1,10 @@ -/*  Copyright (C) 2002     Manuel Novoa III +/* Copyright (C) 2002-2004   Manuel Novoa III    <mjn3@codepoet.org>   * - *  This library is free software; you can redistribute it and/or - *  modify it under the terms of the GNU Library General Public - *  License as published by the Free Software Foundation; either - *  version 2 of the License, or (at your option) any later version. + * GNU Library General Public License (LGPL) version 2 or later.   * - *  This library is distributed in the hope that it will be useful, - *  but WITHOUT ANY WARRANTY; without even the implied warranty of - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - *  Library General Public License for more details. - * - *  You should have received a copy of the GNU Library General Public - *  License along with this library; if not, write to the Free - *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.   */ -/*  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! - * - *  Besides uClibc, I'm using this code in my libc for elks, which is - *  a 16-bit environment with a fairly limited compiler.  It would make - *  things much easier for me if this file isn't modified unnecessarily. - *  In particular, please put any new or replacement functions somewhere - *  else, and modify the makefile to use your version instead. - *  Thanks.  Manuel - * - *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! */ -  /* June 15, 2002     Initial Notes:   *   * Note: It is assumed throught that time_t is either long or unsigned long. @@ -132,6 +111,13 @@   * Dec 14, 2003 Fix some dst issues in _time_mktime().   *   Normalize the tm_isdst value to -1, 0, or 1.   *   If no dst for this timezone, then reset tm_isdst to 0. + * + * May 7, 2004 + *   Change clock() to allow wrapping. + *   Add timegm() function. + *   Make lookup_tzname() static (as it should have been). + *   Have strftime() get timezone information from the passed struct + *     for the %z and %Z conversions when using struct tm extensions.   */  #define _GNU_SOURCE @@ -219,6 +205,13 @@ extern struct tm *_time_t2tm(const time_t *__restrict timer,  extern time_t _time_mktime(struct tm *timeptr, int store_on_success); +extern struct tm *__time_localtime_tzi(const time_t *__restrict timer, +									   struct tm *__restrict result, +									   rule_struct *tzi); + +extern time_t _time_mktime_tzi(struct tm *timeptr, int store_on_success, +							   rule_struct *tzi); +  /**********************************************************************/  #ifdef L_asctime @@ -376,51 +369,63 @@ char *asctime_r(register const struct tm *__restrict ptm,  #include <sys/times.h> -/* Note: According to glibc... - *    CAE XSH, Issue 4, Version 2: <time.h> - *    The value of CLOCKS_PER_SEC is required to be 1 million on all - *    XSI-conformant systems. - */ -  #ifndef __BCC__  #if CLOCKS_PER_SEC != 1000000L  #error unexpected value for CLOCKS_PER_SEC!  #endif  #endif +#ifdef __UCLIBC_CLK_TCK_CONST +# if __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC +#  error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC! +# elif __UCLIBC_CLK_TCK_CONST < 1 +#  error __UCLIBC_CLK_TCK_CONST < 1! +# endif +#endif + +/* Note: SUSv3 notes + * + *   On XSI-conformant systems, CLOCKS_PER_SEC is defined to be one million. + * + *   The value returned by clock() may wrap around on some implementations. + *   For example, on a machine with 32-bit values for clock_t, it wraps + *   after 2147 seconds. + * + * This implies that we should bitwise and with LONG_MAX. + */ +  clock_t clock(void)  {  	struct tms xtms;  	unsigned long t;  	times(&xtms); +  	t = ((unsigned long) xtms.tms_utime) + xtms.tms_stime;  #ifndef __UCLIBC_CLK_TCK_CONST -#error __UCLIBC_CLK_TCK_CONST not defined! -#endif -#undef CLK_TCK -#define CLK_TCK __UCLIBC_CLK_TCK_CONST +# error __UCLIBC_CLK_TCK_CONST not defined! -#if CLK_TCK > CLOCKS_PER_SEC -#error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC! -#elif CLK_TCK < 1 -#error __UCLIBC_CLK_TCK_CONST < 1! -#endif +#elif ((CLOCKS_PER_SEC % __UCLIBC_CLK_TCK_CONST) == 0) + +	/* CLOCKS_PER_SEC == k * __UCLIBC_CLK_TCK_CONST for some integer k >= 1. */ +	return ((t * (CLOCKS_PER_SEC/__UCLIBC_CLK_TCK_CONST)) & LONG_MAX); -#if (CLK_TCK == CLOCKS_PER_SEC) -	return (t <= LONG_MAX) ? t : -1; -#elif (CLOCKS_PER_SEC % CLK_TCK) == 0 -	return (t <= (LONG_MAX / (CLOCKS_PER_SEC/CLK_TCK))) -		? t * (CLOCKS_PER_SEC/CLK_TCK) -		: -1;  #else -	return (t <= ((LONG_MAX / CLOCKS_PER_SEC) * CLK_TCK -				  + ((LONG_MAX % CLOCKS_PER_SEC) * CLK_TCK) / CLOCKS_PER_SEC)) -		? (((t / CLK_TCK) * CLOCKS_PER_SEC) -		   + (((t % CLK_TCK) * CLOCKS_PER_SEC) / CLK_TCK)) -		: -1; + +	/* Unlike the previous case, the scaling factor is not an integer. +	 * So when tms_utime, tms_stime, or their sum wraps, some of the +	 * "visible" bits in the return value are affected.  Nothing we +	 * can really do about this though other than handle tms_utime and +	 * tms_stime seperately and then sum.  But since that doesn't really +	 * buy us much, we don't bother. */ + +	return ((((t / __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC) +			 + ((((t % __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC) +				 / __UCLIBC_CLK_TCK_CONST)) +			 ) & LONG_MAX); +  #endif  } @@ -525,6 +530,24 @@ struct tm *localtime(const time_t *timer)  /**********************************************************************/  #ifdef L_localtime_r +struct tm *localtime_r(register const time_t *__restrict timer, +					   register struct tm *__restrict result) +{ +	TZLOCK; + +	tzset(); + +	__time_localtime_tzi(timer, result, _time_tzinfo); + +	TZUNLOCK; + +	return result; +} + +#endif +/**********************************************************************/ +#ifdef L__time_localtime_tzi +  #ifdef __UCLIBC_HAS_TM_EXTENSIONS__  struct ll_tzname_item; @@ -539,7 +562,7 @@ static ll_tzname_item_t ll_tzname[] = {  	{ NULL, "???" }		  /* Always 2nd. (invalid or out-of-memory) */  }; -const char *lookup_tzname(const char *key) +static const char *lookup_tzname(const char *key)  {  	ll_tzname_item_t *p; @@ -574,9 +597,9 @@ static const unsigned char day_cor[] = { /* non-leap */  /* Note: timezone locking is done by localtime_r. */ -static int tm_isdst(register const struct tm *__restrict ptm) +static int tm_isdst(register const struct tm *__restrict ptm, +					register rule_struct *r)  { -	register rule_struct *r = _time_tzinfo;  	long sec;  	int i, isdst, isleap, day, day0, monlen, mday;  	int oday;					/* Note: oday can be uninitialized. */ @@ -647,21 +670,18 @@ static int tm_isdst(register const struct tm *__restrict ptm)  	return (isdst & 1);  } -struct tm *localtime_r(register const time_t *__restrict timer, -					   register struct tm *__restrict result) +struct tm *__time_localtime_tzi(register const time_t *__restrict timer, +								register struct tm *__restrict result, +								rule_struct *tzi)  {  	time_t x[1];  	long offset;  	int days, dst; -	TZLOCK; - -	tzset(); -  	dst = 0;  	do {  		days = -7; -		offset = 604800L - _time_tzinfo[dst].gmt_offset; +		offset = 604800L - tzi[dst].gmt_offset;  		if (*timer > (LONG_MAX - 604800L)) {  			days = -days;  			offset = -offset; @@ -671,12 +691,11 @@ struct tm *localtime_r(register const time_t *__restrict timer,  		_time_t2tm(x, days, result);  		result->tm_isdst = dst;  #ifdef __UCLIBC_HAS_TM_EXTENSIONS__ -		result->tm_gmtoff = - _time_tzinfo[dst].gmt_offset; -		result->tm_zone = lookup_tzname(_time_tzinfo[dst].tzname); +		result->tm_gmtoff = - tzi[dst].gmt_offset; +		result->tm_zone = lookup_tzname(tzi[dst].tzname);  #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */ -	} while ((++dst < 2) && ((result->tm_isdst = tm_isdst(result)) != 0)); - -	TZUNLOCK; +	} while ((++dst < 2) +			 && ((result->tm_isdst = tm_isdst(result, tzi)) != 0));  	return result;  } @@ -694,6 +713,20 @@ time_t mktime(struct tm *timeptr)  	return  _time_mktime(timeptr, 1);  } +#endif +/**********************************************************************/ +#ifdef L_timegm +/* Like `mktime' but timeptr represents Universal Time, not local time. */ + +time_t timegm(struct tm *timeptr) +{ +	rule_struct gmt_tzinfo[2]; + +	memset(gmt_tzinfo, 0, sizeof(gmt_tzinfo)); +	strcpy(gmt_tzinfo[0].tzname, "GMT"); /* Match glibc behavior here. */ + +	return  _time_mktime_tzi(timeptr, 1, gmt_tzinfo); +}  #endif  /**********************************************************************/ @@ -913,7 +946,9 @@ size_t __XL(strftime)(char *__restrict s, size_t maxsize,  	long tzo;  	register const char *p;  	register const char *o; +#ifndef __UCLIBC_HAS_TM_EXTENSIONS__  	const rule_struct *rsp; +#endif  	const char *stack[MAX_PUSH];  	size_t count;  	size_t o_count; @@ -1027,15 +1062,28 @@ size_t __XL(strftime)(char *__restrict s, size_t maxsize,  					goto OUTPUT;  				} +#ifdef __UCLIBC_HAS_TM_EXTENSIONS__ + +#define RSP_TZUNLOCK	((void) 0) +#define RSP_TZNAME		timeptr->tm_zone +#define RSP_GMT_OFFSET	timeptr->tm_gmtoff + +#else + +#define RSP_TZUNLOCK	TZUNLOCK +#define RSP_TZNAME		rsp->tzname +#define RSP_GMT_OFFSET	rsp->gmt_offset +  				TZLOCK;  				rsp = _time_tzinfo;  				if (timeptr->tm_isdst > 0) {  					++rsp;  				} +#endif  				if (*p == 'Z') { -					o = rsp->tzname; +					o = RSP_TZNAME;  					assert(o != NULL);  #if 0  					if (!o) {	/* PARANOIA */ @@ -1043,15 +1091,15 @@ size_t __XL(strftime)(char *__restrict s, size_t maxsize,  					}  #endif  					o_count = SIZE_MAX; -					TZUNLOCK; +					RSP_TZUNLOCK;  					goto OUTPUT;  				} else {		/* z */  					*s = '+'; -					if ((tzo = -rsp->gmt_offset) < 0) { +					if ((tzo = -RSP_GMT_OFFSET) < 0) {  						tzo = -tzo;  						*s = '-';  					} -					TZUNLOCK; +					RSP_TZUNLOCK;  					++s;  					--count; @@ -1060,6 +1108,7 @@ size_t __XL(strftime)(char *__restrict s, size_t maxsize,  					i = 16 + 6;	/* 0-fill, width = 4 */  				} +  			} else {  				/* TODO: don't need year for U, W */  				for (i=0 ; i < 3 ; i++) { @@ -2087,12 +2136,32 @@ struct tm __time_tm;	/* Global shared by gmtime() and localtime(). */  /**********************************************************************/  #ifdef L__time_mktime +time_t _time_mktime(struct tm *timeptr, int store_on_success) +{ +	time_t t; + +	TZLOCK; + +	tzset(); + +	t = _time_mktime_tzi(timeptr, store_on_success, _time_tzinfo); + +	TZUNLOCK; + +	return t; +} + +#endif +/**********************************************************************/ +#ifdef L__time_mktime_tzi +  static const unsigned char vals[] = {  	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */  	    29,  }; -time_t _time_mktime(struct tm *timeptr, int store_on_success) +time_t _time_mktime_tzi(struct tm *timeptr, int store_on_success, +						rule_struct *tzi)  {  #ifdef __BCC__  	long days, secs; @@ -2106,13 +2175,9 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)  	register const unsigned char *s;  	int d, default_dst; -	TZLOCK; - -	tzset(); -  	memcpy(p, timeptr, sizeof(struct tm)); -	if (!_time_tzinfo[1].tzname[0]) { /* No dst in this timezone, */ +	if (!tzi[1].tzname[0]) { /* No dst in this timezone, */  		p[8] = 0;				/* so set tm_isdst to 0. */  	} @@ -2150,7 +2215,7 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)  	d = p[5] - 1;  	days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);  	secs = p[0] + 60*( p[1] + 60*((long)(p[2])) ) -		+ _time_tzinfo[default_dst].gmt_offset; +		+ tzi[default_dst].gmt_offset;   DST_CORRECT:  	if (secs < 0) {  		secs += 120009600L; @@ -2165,7 +2230,7 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)  	d = p[5] - 1;  	d = -719163L + d*365 + (d/4) - (d/100) + (d/400);  	secs = p[0] -		+ _time_tzinfo[default_dst].gmt_offset +		+ tzi[default_dst].gmt_offset  		+ 60*( p[1]  			   + 60*(p[2]  					 + 24*(((146073L * ((long long)(p[6])) + d) @@ -2183,7 +2248,7 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)  	d = ((struct tm *)p)->tm_isdst;  	t = secs; -	localtime_r(&t, (struct tm *)p); +	__time_localtime_tzi(&t, (struct tm *)p, tzi);  	if (t == ((time_t)(-1))) {	/* Remember, time_t can be unsigned. */  	    goto DONE; @@ -2193,8 +2258,8 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)  #ifdef __BCC__  		secs -= (days * 86400L);  #endif -		secs += (_time_tzinfo[1-default_dst].gmt_offset -				 - _time_tzinfo[default_dst].gmt_offset); +		secs += (tzi[1-default_dst].gmt_offset +				 - tzi[default_dst].gmt_offset);  		goto DST_CORRECT;  	} @@ -2205,8 +2270,6 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)   DONE: -	TZUNLOCK; -  	return t;  } @@ -2254,7 +2317,3 @@ int dysize(int year)  #endif  /**********************************************************************/ -/* Like `mktime', but for TP represents Universal Time, not local time.  */ -/* time_t timegm(struct tm *tp) */ - - | 
