diff options
author | Elliott Hughes <enh@google.com> | 2013-07-12 17:31:11 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2013-07-12 17:52:44 -0700 |
commit | ce4783ce76a4ef888466e02e4c6f3a0a3910bce8 (patch) | |
tree | 4bc51cd70edd4df6d6489d1ff8b4472f293f27b4 /libc/tzcode | |
parent | 3db1f359e9f218f5f73a7a9f4d80e4be362a526e (diff) | |
download | bionic-ce4783ce76a4ef888466e02e4c6f3a0a3910bce8.zip bionic-ce4783ce76a4ef888466e02e4c6f3a0a3910bce8.tar.gz bionic-ce4783ce76a4ef888466e02e4c6f3a0a3910bce8.tar.bz2 |
Upgrade to tzcode2013d.
Well, kinda... localtime.c still contains a bunch of Android-specific
hacks, as does strftime.c. But the other files are now exactly the same
as upstream.
This catches up with several years of bug fixes, and fixes most of the
compiler warnings that were in this code. (Just two remain.)
Bug: 1744909
Change-Id: I2ddfecb6fd408c847397c17afb0fff859e27feef
Diffstat (limited to 'libc/tzcode')
-rw-r--r-- | libc/tzcode/asctime.c | 114 | ||||
-rw-r--r-- | libc/tzcode/difftime.c | 101 | ||||
-rw-r--r-- | libc/tzcode/localtime.c | 1011 | ||||
-rw-r--r-- | libc/tzcode/private.h | 281 | ||||
-rw-r--r-- | libc/tzcode/strftime.c | 12 | ||||
-rw-r--r-- | libc/tzcode/tzfile.h | 166 |
6 files changed, 801 insertions, 884 deletions
diff --git a/libc/tzcode/asctime.c b/libc/tzcode/asctime.c index 22bba34..152b0db 100644 --- a/libc/tzcode/asctime.c +++ b/libc/tzcode/asctime.c @@ -9,12 +9,6 @@ ** whereas the output of asctime is supposed to be constant. */ -#ifndef lint -#ifndef NOID -static char elsieid[] = "@(#)asctime.c 8.2"; -#endif /* !defined NOID */ -#endif /* !defined lint */ - /*LINTLIBRARY*/ #include "private.h" @@ -39,9 +33,9 @@ static char elsieid[] = "@(#)asctime.c 8.2"; ** but many implementations pad anyway; most likely the standards are buggy. */ #ifdef __GNUC__ -#define ASCTIME_FMT "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %-4s\n" +#define ASCTIME_FMT "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %-4s\n" #else /* !defined __GNUC__ */ -#define ASCTIME_FMT "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %-4s\n" +#define ASCTIME_FMT "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %-4s\n" #endif /* !defined __GNUC__ */ /* ** For years that are more than four digits we put extra spaces before the year @@ -50,12 +44,12 @@ static char elsieid[] = "@(#)asctime.c 8.2"; ** that no output is better than wrong output). */ #ifdef __GNUC__ -#define ASCTIME_FMT_B "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %s\n" +#define ASCTIME_FMT_B "%.3s %.3s%3d %2.2d:%2.2d:%2.2d %s\n" #else /* !defined __GNUC__ */ -#define ASCTIME_FMT_B "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %s\n" +#define ASCTIME_FMT_B "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %s\n" #endif /* !defined __GNUC__ */ -#define STD_ASCTIME_BUF_SIZE 26 +#define STD_ASCTIME_BUF_SIZE 26 /* ** Big enough for something such as ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n @@ -66,64 +60,65 @@ static char elsieid[] = "@(#)asctime.c 8.2"; ** as an example; the define below calculates the maximum for the system at ** hand. */ -#define MAX_ASCTIME_BUF_SIZE (2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1) +#define MAX_ASCTIME_BUF_SIZE (2*3+5*INT_STRLEN_MAXIMUM(int)+7+2+1+1) -static char buf_asctime[MAX_ASCTIME_BUF_SIZE]; +static char buf_asctime[MAX_ASCTIME_BUF_SIZE]; /* ** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, 2004 Edition. */ char * -asctime_r(timeptr, buf) -register const struct tm * timeptr; -char * buf; +asctime_r(register const struct tm *timeptr, char *buf) { - static const char wday_name[][3] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - }; - static const char mon_name[][3] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - register const char * wn; - register const char * mn; - char year[INT_STRLEN_MAXIMUM(int) + 2]; - char result[MAX_ASCTIME_BUF_SIZE]; + static const char wday_name[][3] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static const char mon_name[][3] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + register const char * wn; + register const char * mn; + char year[INT_STRLEN_MAXIMUM(int) + 2]; + char result[MAX_ASCTIME_BUF_SIZE]; - if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK) - wn = "???"; - else wn = wday_name[timeptr->tm_wday]; - if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR) - mn = "???"; - else mn = mon_name[timeptr->tm_mon]; - /* - ** Use strftime's %Y to generate the year, to avoid overflow problems - ** when computing timeptr->tm_year + TM_YEAR_BASE. - ** Assume that strftime is unaffected by other out-of-range members - ** (e.g., timeptr->tm_mday) when processing "%Y". - */ - (void) strftime(year, sizeof year, "%Y", timeptr); - /* - ** We avoid using snprintf since it's not available on all systems. - */ - (void) sprintf(result, - ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B), - wn, mn, - timeptr->tm_mday, timeptr->tm_hour, - timeptr->tm_min, timeptr->tm_sec, - year); - if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime) { - (void) strcpy(buf, result); - return buf; - } else { + if (timeptr == NULL) { + errno = EINVAL; + return strcpy(buf, "??? ??? ?? ??:??:?? ????\n"); + } + if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK) + wn = "???"; + else wn = wday_name[timeptr->tm_wday]; + if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR) + mn = "???"; + else mn = mon_name[timeptr->tm_mon]; + /* + ** Use strftime's %Y to generate the year, to avoid overflow problems + ** when computing timeptr->tm_year + TM_YEAR_BASE. + ** Assume that strftime is unaffected by other out-of-range members + ** (e.g., timeptr->tm_mday) when processing "%Y". + */ + (void) strftime(year, sizeof year, "%Y", timeptr); + /* + ** We avoid using snprintf since it's not available on all systems. + */ + (void) sprintf(result, + ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B), + wn, mn, + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec, + year); + if (strlen(result) < STD_ASCTIME_BUF_SIZE || buf == buf_asctime) + return strcpy(buf, result); + else { #ifdef EOVERFLOW - errno = EOVERFLOW; + errno = EOVERFLOW; #else /* !defined EOVERFLOW */ - errno = EINVAL; + errno = EINVAL; #endif /* !defined EOVERFLOW */ - return NULL; - } + return NULL; + } } /* @@ -131,8 +126,7 @@ char * buf; */ char * -asctime(timeptr) -register const struct tm * timeptr; +asctime(register const struct tm *timeptr) { - return asctime_r(timeptr, buf_asctime); + return asctime_r(timeptr, buf_asctime); } diff --git a/libc/tzcode/difftime.c b/libc/tzcode/difftime.c index f7581a4..fcd18ce 100644 --- a/libc/tzcode/difftime.c +++ b/libc/tzcode/difftime.c @@ -3,63 +3,54 @@ ** 1996-06-05 by Arthur David Olson. */ -#ifndef lint -#ifndef NOID -static char elsieid[] = "@(#)difftime.c 8.1"; -#endif /* !defined NOID */ -#endif /* !defined lint */ - /*LINTLIBRARY*/ -#include "private.h" /* for time_t, TYPE_INTEGRAL, and TYPE_SIGNED */ +#include "private.h" /* for time_t, TYPE_INTEGRAL, and TYPE_SIGNED */ -double -difftime(time1, time0) -const time_t time1; -const time_t time0; +double ATTRIBUTE_CONST +difftime(const time_t time1, const time_t time0) { - /* - ** If (sizeof (double) > sizeof (time_t)) simply convert and subtract - ** (assuming that the larger type has more precision). - ** This is the common real-world case circa 2004. - */ - if (sizeof (double) > sizeof (time_t)) - return (double) time1 - (double) time0; - if (!TYPE_INTEGRAL(time_t)) { - /* - ** time_t is floating. - */ - return time1 - time0; - } - if (!TYPE_SIGNED(time_t)) { - /* - ** time_t is integral and unsigned. - ** The difference of two unsigned values can't overflow - ** if the minuend is greater than or equal to the subtrahend. - */ - if (time1 >= time0) - return time1 - time0; - else return -((double) (time0 - time1)); - } - /* - ** time_t is integral and signed. - ** Handle cases where both time1 and time0 have the same sign - ** (meaning that their difference cannot overflow). - */ - if ((time1 < 0) == (time0 < 0)) - return time1 - time0; - /* - ** time1 and time0 have opposite signs. - ** Punt if unsigned long is too narrow. - */ - if (sizeof (unsigned long) < sizeof (time_t)) - return (double) time1 - (double) time0; - /* - ** Stay calm...decent optimizers will eliminate the complexity below. - */ - if (time1 >= 0 /* && time0 < 0 */) - return (unsigned long) time1 + - (unsigned long) (-(time0 + 1)) + 1; - return -(double) ((unsigned long) time0 + - (unsigned long) (-(time1 + 1)) + 1); + /* + ** If (sizeof (double) > sizeof (time_t)) simply convert and subtract + ** (assuming that the larger type has more precision). + */ + if (sizeof (double) > sizeof (time_t)) + return (double) time1 - (double) time0; + if (!TYPE_INTEGRAL(time_t)) { + /* + ** time_t is floating. + */ + return time1 - time0; + } + if (!TYPE_SIGNED(time_t)) { + /* + ** time_t is integral and unsigned. + ** The difference of two unsigned values can't overflow + ** if the minuend is greater than or equal to the subtrahend. + */ + if (time1 >= time0) + return time1 - time0; + else return -(double) (time0 - time1); + } + /* + ** time_t is integral and signed. + ** Handle cases where both time1 and time0 have the same sign + ** (meaning that their difference cannot overflow). + */ + if ((time1 < 0) == (time0 < 0)) + return time1 - time0; + /* + ** time1 and time0 have opposite signs. + ** Punt if uintmax_t is too narrow. + ** This suffers from double rounding; attempt to lessen that + ** by using long double temporaries. + */ + if (sizeof (uintmax_t) < sizeof (time_t)) + return (long double) time1 - (long double) time0; + /* + ** Stay calm...decent optimizers will eliminate the complexity below. + */ + if (time1 >= 0 /* && time0 < 0 */) + return (uintmax_t) time1 + (uintmax_t) (-1 - time0) + 1; + return -(double) ((uintmax_t) time0 + (uintmax_t) (-1 - time1) + 1); } diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c index 0c4d268..d1b49e5 100644 --- a/libc/tzcode/localtime.c +++ b/libc/tzcode/localtime.c @@ -3,12 +3,6 @@ ** 1996-06-05 by Arthur David Olson. */ -#ifndef lint -#ifndef NOID -static char elsieid[] = "@(#)localtime.c 8.3"; -#endif /* !defined NOID */ -#endif /* !defined lint */ - /* ** Leap second handling from Bradley White. ** POSIX-style TZ environment variable handling from Guy Harris. @@ -21,9 +15,6 @@ static char elsieid[] = "@(#)localtime.c 8.3"; #include "fcntl.h" #include "float.h" /* for FLT_MAX and DBL_MAX */ -#include "thread_private.h" -#include <sys/system_properties.h> - #ifndef TZ_ABBR_MAX_LEN #define TZ_ABBR_MAX_LEN 16 #endif /* !defined TZ_ABBR_MAX_LEN */ @@ -54,53 +45,12 @@ static char elsieid[] = "@(#)localtime.c 8.3"; # define XLOG(x) do{}while (0) #endif -/* Add the following function implementations: - * timelocal() - * timegm() - * time2posix() - * posix2time() - */ -#define STD_INSPIRED 1 - -/* THREAD-SAFETY SUPPORT GOES HERE */ -static pthread_mutex_t _tzMutex = PTHREAD_MUTEX_INITIALIZER; - -static __inline__ void _tzLock(void) -{ - if (__isthreaded) - pthread_mutex_lock(&_tzMutex); -} - -static __inline__ void _tzUnlock(void) -{ - if (__isthreaded) - pthread_mutex_unlock(&_tzMutex); -} - -/* Complex computations to determine the min/max of time_t depending - * on TYPE_BIT / TYPE_SIGNED / TYPE_INTEGRAL. - * These macros cannot be used in pre-processor directives, so we - * let the C compiler do the work, which makes things a bit funky. - */ -static const time_t TIME_T_MAX = - TYPE_INTEGRAL(time_t) ? - ( TYPE_SIGNED(time_t) ? - ~((time_t)1 << (TYPE_BIT(time_t)-1)) - : - ~(time_t)0 - ) - : /* if time_t is a floating point number */ - ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MAX : (time_t)FLT_MAX ); - -static const time_t TIME_T_MIN = - TYPE_INTEGRAL(time_t) ? - ( TYPE_SIGNED(time_t) ? - ((time_t)1 << (TYPE_BIT(time_t)-1)) - : - 0 - ) - : - ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MIN : (time_t)FLT_MIN ); +/* BEGIN android-added: thread-safety. */ +#include <pthread.h> +static pthread_mutex_t _tzMutex = PTHREAD_MUTEX_INITIALIZER; +static inline void _tzLock(void) { pthread_mutex_lock(&_tzMutex); } +static inline void _tzUnlock(void) { pthread_mutex_unlock(&_tzMutex); } +/* END android-added */ #ifndef WILDABBR /* @@ -141,16 +91,16 @@ static const char gmt[] = "GMT"; #endif /* !defined TZDEFDST */ struct ttinfo { /* time type information */ - long tt_gmtoff; /* UTC offset in seconds */ - int tt_isdst; /* used to set tm_isdst */ - int tt_abbrind; /* abbreviation list index */ - int tt_ttisstd; /* TRUE if transition is std time */ - int tt_ttisgmt; /* TRUE if transition is UTC */ + int_fast32_t tt_gmtoff; /* UTC offset in seconds */ + int tt_isdst; /* used to set tm_isdst */ + int tt_abbrind; /* abbreviation list index */ + int tt_ttisstd; /* TRUE if transition is std time */ + int tt_ttisgmt; /* TRUE if transition is UTC */ }; struct lsinfo { /* leap second information */ - time_t ls_trans; /* transition time */ - long ls_corr; /* correction to apply */ + time_t ls_trans; /* transition time */ + int_fast64_t ls_corr; /* correction to apply */ }; #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) @@ -162,10 +112,6 @@ struct lsinfo { /* leap second information */ #define MY_TZNAME_MAX 255 #endif /* !defined TZNAME_MAX */ -/* XXX: This code should really use time64_t instead of time_t - * but we can't change it without re-generating the index - * file first with the correct data. - */ struct state { int leapcnt; int timecnt; @@ -179,14 +125,15 @@ struct state { char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), (2 * (MY_TZNAME_MAX + 1)))]; struct lsinfo lsis[TZ_MAX_LEAPS]; + int defaulttype; /* for early times or if no transitions */ }; struct rule { - int r_type; /* type of rule--see below */ - int r_day; /* day number of rule */ - int r_week; /* week number of rule */ - int r_mon; /* month number of rule */ - long r_time; /* transition time of rule */ + int r_type; /* type of rule--see below */ + int r_day; /* day number of rule */ + int r_week; /* week number of rule */ + int r_mon; /* month number of rule */ + int_fast32_t r_time; /* transition time of rule */ }; #define JULIAN_DAY 0 /* Jn - Julian day */ @@ -200,51 +147,54 @@ struct rule { /* NOTE: all internal functions assume that _tzLock() was already called */ static int __bionic_open_tzdata(const char*, int*); -static long detzcode P((const char * codep)); -static time_t detzcode64 P((const char * codep)); -static int differ_by_repeat P((time_t t1, time_t t0)); -static const char * getzname P((const char * strp)); -static const char * getqzname P((const char * strp, const int delim)); -static const char * getnum P((const char * strp, int * nump, int min, - int max)); -static const char * getsecs P((const char * strp, long * secsp)); -static const char * getoffset P((const char * strp, long * offsetp)); -static const char * getrule P((const char * strp, struct rule * rulep)); -static void gmtload P((struct state * sp)); -static struct tm * gmtsub P((const time_t * timep, long offset, - struct tm * tmp, const struct state * sp)); // android-changed: added sp. -static struct tm * localsub P((const time_t * timep, long offset, - struct tm * tmp, const struct state * sp)); // android-changed: added sp. -static int increment_overflow P((int * number, int delta)); -static int leaps_thru_end_of P((int y)); -static int long_increment_overflow P((long * number, int delta)); -static int long_normalize_overflow P((long * tensptr, - int * unitsptr, int base)); -static int normalize_overflow P((int * tensptr, int * unitsptr, - int base)); -static void settzname P((void)); -static time_t time1 P((struct tm * tmp, - struct tm * (*funcp) P((const time_t *, - long, struct tm *, const struct state *)), // android-changed: added state*. - long offset, const struct state * sp)); // android-changed: added sp. -static time_t time2 P((struct tm *tmp, - struct tm * (*funcp) P((const time_t *, - long, struct tm*, const struct state *)), // android-changed: added state*. - long offset, int * okayp, const struct state * sp)); // android-changed: added sp. -static time_t time2sub P((struct tm *tmp, - struct tm * (*funcp) P((const time_t *, - long, struct tm*, const struct state *)), // android-changed: added state*. - long offset, int * okayp, int do_norm_secs, const struct state * sp)); // android-change: added sp. -static struct tm * timesub P((const time_t * timep, long offset, - const struct state * sp, struct tm * tmp)); -static int tmcomp P((const struct tm * atmp, - const struct tm * btmp)); -static time_t transtime P((time_t janfirst, int year, - const struct rule * rulep, long offset)); -static int tzload P((const char * name, struct state * sp, - int doextend)); -static int tzparse P((const char * name, struct state * sp, - int lastditch)); +static int_fast32_t detzcode(const char * codep); +static time_t detzcode64(const char * codep); +static int differ_by_repeat(time_t t1, time_t t0); +static const char * getzname(const char * strp) ATTRIBUTE_PURE; +static const char * getqzname(const char * strp, const int delim) + ATTRIBUTE_PURE; +static const char * getnum(const char * strp, int * nump, int min, + int max); +static const char * getsecs(const char * strp, int_fast32_t * secsp); +static const char * getoffset(const char * strp, int_fast32_t * offsetp); +static const char * getrule(const char * strp, struct rule * rulep); +static void gmtload(struct state * sp); +static struct tm * gmtsub(const time_t * timep, const int_fast32_t offset, + struct tm * tmp, const struct state * sp); // android-changed: added sp. +static struct tm * localsub(const time_t * timep, int_fast32_t offset, + struct tm * tmp, const struct state * sp); // android-changed: added sp. +static int increment_overflow(int * number, int delta); +static int leaps_thru_end_of(int y) ATTRIBUTE_PURE; +static int increment_overflow32(int_fast32_t * number, int delta); +static int normalize_overflow32(int_fast32_t * tensptr, + int * unitsptr, int base); +static int normalize_overflow(int * tensptr, int * unitsptr, + int base); +static void settzname(void); +static time_t time1(struct tm * tmp, + struct tm * (*funcp)(const time_t *, + int_fast32_t, struct tm *, const struct state *), // android-changed: added state*. + int_fast32_t offset, const struct state * sp); // android-changed: added sp. +static time_t time2(struct tm * const tmp, + struct tm * (*const funcp)(const time_t *, + int_fast32_t, struct tm*, const struct state *), // android-changed: added state*. + int_fast32_t offset, int * okayp, const struct state * sp); // android-changed: added sp. +static time_t time2sub(struct tm *tmp, + struct tm * (*funcp) (const time_t *, + int_fast32_t, struct tm*, const struct state *), // android-changed: added state*. + int_fast32_t offset, int * okayp, int do_norm_secs, const struct state * sp); // android-change: added sp. +static struct tm * timesub(const time_t * timep, int_fast32_t offset, + const struct state * sp, struct tm * tmp); +static int tmcomp(const struct tm * atmp, + const struct tm * btmp); +static time_t transtime(time_t janfirst, int year, + const struct rule * rulep, int_fast32_t offset) + ATTRIBUTE_PURE; +static int typesequiv(const struct state * sp, int a, int b); +static int tzload(const char * name, struct state * sp, + int doextend); +static int tzparse(const char * name, struct state * sp, + int lastditch); #ifdef ALL_STATE static struct state * lclptr; @@ -290,34 +240,32 @@ int daylight = 0; time_t altzone = 0; #endif /* defined ALTZONE */ -static long -detzcode(codep) -const char * const codep; +static int_fast32_t +detzcode(const char *const codep) { - register long result; - register int i; + register int_fast32_t result; + register int i; - result = (codep[0] & 0x80) ? ~0L : 0; - for (i = 0; i < 4; ++i) - result = (result << 8) | (codep[i] & 0xff); - return result; + result = (codep[0] & 0x80) ? -1 : 0; + for (i = 0; i < 4; ++i) + result = (result << 8) | (codep[i] & 0xff); + return result; } static time_t -detzcode64(codep) -const char * const codep; +detzcode64(const char *const codep) { - register time_t result; - register int i; + register time_t result; + register int i; - result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0; - for (i = 0; i < 8; ++i) - result = result * 256 + (codep[i] & 0xff); - return result; + result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0; + for (i = 0; i < 8; ++i) + result = result * 256 + (codep[i] & 0xff); + return result; } static void -settzname P((void)) +settzname(void) { register struct state * const sp = lclptr; register int i; @@ -337,34 +285,33 @@ settzname P((void)) return; } #endif /* defined ALL_STATE */ + /* + ** And to get the latest zone names into tzname. . . + */ for (i = 0; i < sp->typecnt; ++i) { register const struct ttinfo * const ttisp = &sp->ttis[i]; + tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind]; + } + for (i = 0; i < sp->timecnt; ++i) { + register const struct ttinfo * const ttisp = + &sp->ttis[ + sp->types[i]]; + tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind]; #ifdef USG_COMPAT if (ttisp->tt_isdst) daylight = 1; - if (i == 0 || !ttisp->tt_isdst) + if (!ttisp->tt_isdst) timezone = -(ttisp->tt_gmtoff); #endif /* defined USG_COMPAT */ #ifdef ALTZONE - if (i == 0 || ttisp->tt_isdst) + if (ttisp->tt_isdst) altzone = -(ttisp->tt_gmtoff); #endif /* defined ALTZONE */ } /* - ** And to get the latest zone names into tzname. . . - */ - for (i = 0; i < sp->timecnt; ++i) { - register const struct ttinfo * const ttisp = - &sp->ttis[ - sp->types[i]]; - - tzname[ttisp->tt_isdst] = - &sp->chars[ttisp->tt_abbrind]; - } - /* ** Finally, scrub the abbreviations. ** First, replace bogus characters. */ @@ -385,113 +332,70 @@ settzname P((void)) } static int -differ_by_repeat(t1, t0) -const time_t t1; -const time_t t0; +differ_by_repeat(const time_t t1, const time_t t0) { - if (TYPE_INTEGRAL(time_t) && - TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS) - return 0; -#if SECSPERREPEAT_BITS <= 32 /* to avoid compiler warning (condition is always false) */ - return (t1 - t0) == SECSPERREPEAT; -#else - return 0; -#endif -} - -static int toint(unsigned char *s) { - return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; + if (TYPE_INTEGRAL(time_t) && + TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS) + return 0; + return t1 - t0 == SECSPERREPEAT; } static int -tzload(const char* name, struct state* const sp, const int doextend) +tzload(register const char* name, register struct state* const sp, + register const int doextend) { register const char * p; register int i; register int fid; register int stored; register int nread; - union { + typedef union { struct tzhead tzhead; char buf[2 * sizeof(struct tzhead) + 2 * sizeof *sp + 4 * TZ_MAX_TIMES]; - } u; - int toread = sizeof u.buf; - - if (name == NULL && (name = TZDEFAULT) == NULL) { - XLOG(("tzload: null 'name' parameter\n" )); - return -1; - } - { - register int doaccess; - /* - ** Section 4.9.1 of the C standard says that - ** "FILENAME_MAX expands to an integral constant expression - ** that is the size needed for an array of char large enough - ** to hold the longest file name string that the implementation - ** guarantees can be opened." - */ - char fullname[FILENAME_MAX + 1]; - char *origname = (char*) name; + } u_t; +#ifdef ALL_STATE + register u_t * up; - if (name[0] == ':') - ++name; - doaccess = name[0] == '/'; - if (!doaccess) { - if ((p = TZDIR) == NULL) { - XLOG(("tzload: null TZDIR macro ?\n" )); - return -1; - } - if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) { - XLOG(( "tzload: path too long: %s/%s\n", p, name )); - return -1; - } - (void) strcpy(fullname, p); - (void) strcat(fullname, "/"); - (void) strcat(fullname, name); - /* - ** Set doaccess if '.' (as in "../") shows up in name. - */ - if (strchr(name, '.') != NULL) - doaccess = TRUE; - name = fullname; - } - if (doaccess && access(name, R_OK) != 0) { - XLOG(( "tzload: could not find '%s'\n", name )); - return -1; - } - if ((fid = open(name, OPEN_MODE)) == -1) { - fid = __bionic_open_tzdata(origname, &toread); - if (fid < 0) { - return -1; - } - } + up = (u_t *) calloc(1, sizeof *up); + if (up == NULL) + return -1; +#else /* !defined ALL_STATE */ + u_t u; + register u_t * const up = &u; +#endif /* !defined ALL_STATE */ + + sp->goback = sp->goahead = FALSE; + if (name == NULL && (name = TZDEFAULT) == NULL) + goto oops; + int toread; + fid = __bionic_open_tzdata(name, &toread); + if (fid < 0) { + return -1; } - nread = read(fid, u.buf, toread); - if (close(fid) < 0 || nread <= 0) { - XLOG(( "tzload: could not read content of '%s'\n", DATAFILE )); - return -1; - } + nread = read(fid, up->buf, toread); + if (close(fid) < 0 || nread <= 0) + goto oops; for (stored = 4; stored <= 8; stored *= 2) { int ttisstdcnt; int ttisgmtcnt; - ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt); - ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt); - sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt); - sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt); - sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt); - sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt); - p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt; + ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt); + ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt); + sp->leapcnt = (int) detzcode(up->tzhead.tzh_leapcnt); + sp->timecnt = (int) detzcode(up->tzhead.tzh_timecnt); + sp->typecnt = (int) detzcode(up->tzhead.tzh_typecnt); + sp->charcnt = (int) detzcode(up->tzhead.tzh_charcnt); + p = up->tzhead.tzh_charcnt + sizeof up->tzhead.tzh_charcnt; if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) - return -1; - if (nread - (p - u.buf) < + goto oops; + if (nread - (p - up->buf) < sp->timecnt * stored + /* ats */ sp->timecnt + /* types */ sp->typecnt * 6 + /* ttinfos */ @@ -499,7 +403,7 @@ tzload(const char* name, struct state* const sp, const int doextend) sp->leapcnt * (stored + 4) + /* lsinfos */ ttisstdcnt + /* ttisstds */ ttisgmtcnt) /* ttisgmts */ - return -1; + goto oops; for (i = 0; i < sp->timecnt; ++i) { sp->ats[i] = (stored == 4) ? detzcode(p) : detzcode64(p); @@ -508,7 +412,7 @@ tzload(const char* name, struct state* const sp, const int doextend) for (i = 0; i < sp->timecnt; ++i) { sp->types[i] = (unsigned char) *p++; if (sp->types[i] >= sp->typecnt) - return -1; + goto oops; } for (i = 0; i < sp->typecnt; ++i) { register struct ttinfo * ttisp; @@ -518,11 +422,11 @@ tzload(const char* name, struct state* const sp, const int doextend) p += 4; ttisp->tt_isdst = (unsigned char) *p++; if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1) - return -1; + goto oops; ttisp->tt_abbrind = (unsigned char) *p++; if (ttisp->tt_abbrind < 0 || ttisp->tt_abbrind > sp->charcnt) - return -1; + goto oops; } for (i = 0; i < sp->charcnt; ++i) sp->chars[i] = *p++; @@ -547,7 +451,7 @@ tzload(const char* name, struct state* const sp, const int doextend) ttisp->tt_ttisstd = *p++; if (ttisp->tt_ttisstd != TRUE && ttisp->tt_ttisstd != FALSE) - return -1; + goto oops; } } for (i = 0; i < sp->typecnt; ++i) { @@ -560,7 +464,7 @@ tzload(const char* name, struct state* const sp, const int doextend) ttisp->tt_ttisgmt = *p++; if (ttisp->tt_ttisgmt != TRUE && ttisp->tt_ttisgmt != FALSE) - return -1; + goto oops; } } /* @@ -568,36 +472,47 @@ tzload(const char* name, struct state* const sp, const int doextend) ** signed time_t system but using a data file with ** unsigned values (or vice versa). */ - for (i = 0; i < sp->timecnt - 2; ++i) - if (sp->ats[i] > sp->ats[i + 1]) { - ++i; - if (TYPE_SIGNED(time_t)) { - /* - ** Ignore the end (easy). - */ - sp->timecnt = i; - } else { - /* - ** Ignore the beginning (harder). - */ - register int j; - - for (j = 0; j + i < sp->timecnt; ++j) { - sp->ats[j] = sp->ats[j + i]; - sp->types[j] = sp->types[j + i]; + for (i = 0; i < sp->timecnt; ++i) + if ((i < sp->timecnt - 1 && + sp->ats[i] > sp->ats[i + 1]) || + (i == sp->timecnt - 1 && !TYPE_SIGNED(time_t) && + sp->ats[i] > + ((stored == 4) ? INT32_MAX : INT64_MAX))) { + if (TYPE_SIGNED(time_t)) { + /* + ** Ignore the end (easy). + */ + sp->timecnt = i + 1; + } else { + /* + ** Ignore the beginning (harder). + */ + register int j; + + /* + ** Keep the record right before the + ** epoch boundary, + ** but tweak it so that it starts + ** right with the epoch + ** (thanks to Doug Bailey). + */ + sp->ats[i] = 0; + for (j = 0; j + i < sp->timecnt; ++j) { + sp->ats[j] = sp->ats[j + i]; + sp->types[j] = sp->types[j + i]; + } + sp->timecnt = j; } - sp->timecnt = j; - } - break; + break; } /* ** If this is an old file, we're done. */ - if (u.tzhead.tzh_version[0] == '\0') + if (up->tzhead.tzh_version[0] == '\0') break; - nread -= p - u.buf; + nread -= p - up->buf; for (i = 0; i < nread; ++i) - u.buf[i] = p[i]; + up->buf[i] = p[i]; /* ** If this is a narrow integer time_t system, we're done. */ @@ -605,13 +520,13 @@ tzload(const char* name, struct state* const sp, const int doextend) break; } if (doextend && nread > 2 && - u.buf[0] == '\n' && u.buf[nread - 1] == '\n' && + up->buf[0] == '\n' && up->buf[nread - 1] == '\n' && sp->typecnt + 2 <= TZ_MAX_TYPES) { struct state ts; register int result; - u.buf[nread - 1] = '\0'; - result = tzparse(&u.buf[1], &ts, FALSE); + up->buf[nread - 1] = '\0'; + result = tzparse(&up->buf[1], &ts, FALSE); if (result == 0 && ts.typecnt == 2 && sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) { for (i = 0; i < 2; ++i) @@ -639,16 +554,87 @@ tzload(const char* name, struct state* const sp, const int doextend) sp->ttis[sp->typecnt++] = ts.ttis[1]; } } - i = 2 * YEARSPERREPEAT; - sp->goback = sp->goahead = sp->timecnt > i; - sp->goback &= sp->types[i] == sp->types[0] && - differ_by_repeat(sp->ats[i], sp->ats[0]); - sp->goahead &= - sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] && - differ_by_repeat(sp->ats[sp->timecnt - 1], - sp->ats[sp->timecnt - 1 - i]); - XLOG(( "tzload: load ok !!\n" )); - return 0; + if (sp->timecnt > 1) { + for (i = 1; i < sp->timecnt; ++i) + if (typesequiv(sp, sp->types[i], sp->types[0]) && + differ_by_repeat(sp->ats[i], sp->ats[0])) { + sp->goback = TRUE; + break; + } + for (i = sp->timecnt - 2; i >= 0; --i) + if (typesequiv(sp, sp->types[sp->timecnt - 1], + sp->types[i]) && + differ_by_repeat(sp->ats[sp->timecnt - 1], + sp->ats[i])) { + sp->goahead = TRUE; + break; + } + } + /* + ** If type 0 is is unused in transitions, + ** it's the type to use for early times. + */ + for (i = 0; i < sp->typecnt; ++i) + if (sp->types[i] == 0) + break; + i = (i >= sp->typecnt) ? 0 : -1; + /* + ** Absent the above, + ** if there are transition times + ** and the first transition is to a daylight time + ** find the standard type less than and closest to + ** the type of the first transition. + */ + if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) { + i = sp->types[0]; + while (--i >= 0) + if (!sp->ttis[i].tt_isdst) + break; + } + /* + ** If no result yet, find the first standard type. + ** If there is none, punt to type zero. + */ + if (i < 0) { + i = 0; + while (sp->ttis[i].tt_isdst) + if (++i >= sp->typecnt) { + i = 0; + break; + } + } + sp->defaulttype = i; +#ifdef ALL_STATE + free(up); +#endif /* defined ALL_STATE */ + return 0; +oops: +#ifdef ALL_STATE + free(up); +#endif /* defined ALL_STATE */ + return -1; +} + +static int +typesequiv(const struct state *const sp, const int a, const int b) +{ + register int result; + + if (sp == NULL || + a < 0 || a >= sp->typecnt || + b < 0 || b >= sp->typecnt) + result = FALSE; + else { + register const struct ttinfo * ap = &sp->ttis[a]; + register const struct ttinfo * bp = &sp->ttis[b]; + result = ap->tt_gmtoff == bp->tt_gmtoff && + ap->tt_isdst == bp->tt_isdst && + ap->tt_ttisstd == bp->tt_ttisstd && + ap->tt_ttisgmt == bp->tt_ttisgmt && + strcmp(&sp->chars[ap->tt_abbrind], + &sp->chars[bp->tt_abbrind]) == 0; + } + return result; } static const int mon_lengths[2][MONSPERYEAR] = { @@ -667,8 +653,7 @@ static const int year_lengths[2] = { */ static const char * -getzname(strp) -register const char * strp; +getzname(register const char * strp) { register char c; @@ -705,11 +690,7 @@ getqzname(register const char *strp, const int delim) */ static const char * -getnum(strp, nump, min, max) -register const char * strp; -int * const nump; -const int min; -const int max; +getnum(register const char * strp, int * const nump, const int min, const int max) { register char c; register int num; @@ -738,9 +719,7 @@ const int max; */ static const char * -getsecs(strp, secsp) -register const char * strp; -long * const secsp; +getsecs(register const char *strp, int_fast32_t *const secsp) { int num; @@ -753,7 +732,7 @@ long * const secsp; strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); if (strp == NULL) return NULL; - *secsp = num * (long) SECSPERHOUR; + *secsp = num * (int_fast32_t) SECSPERHOUR; if (*strp == ':') { ++strp; strp = getnum(strp, &num, 0, MINSPERHOUR - 1); @@ -780,9 +759,7 @@ long * const secsp; */ static const char * -getoffset(strp, offsetp) -register const char * strp; -long * const offsetp; +getoffset(register const char *strp, int_fast32_t *const offsetp) { register int neg = 0; @@ -807,9 +784,7 @@ long * const offsetp; */ static const char * -getrule(strp, rulep) -const char * strp; -register struct rule * const rulep; +getrule(const char * strp, register struct rule * const rulep) { if (*strp == 'J') { /* @@ -861,11 +836,8 @@ register struct rule * const rulep; */ static time_t -transtime(janfirst, year, rulep, offset) -const time_t janfirst; -const int year; -register const struct rule * const rulep; -const long offset; +transtime(const time_t janfirst, const int year, + register const struct rule *const rulep, const int_fast32_t offset) { register int leapyear; register time_t value; @@ -956,21 +928,20 @@ const long offset; */ static int -tzparse(name, sp, lastditch) -const char * name; -register struct state * const sp; -const int lastditch; +tzparse(const char * name, register struct state * const sp, + const int lastditch) { const char * stdname; const char * dstname; size_t stdlen; size_t dstlen; - long stdoffset; - long dstoffset; - register time_t * atp; + int_fast32_t stdoffset; + int_fast32_t dstoffset; + register time_t * atp; register unsigned char * typep; register char * cp; register int load_result; + static struct ttinfo zttinfo; INITIALIZE(dstname); stdname = name; @@ -1002,7 +973,6 @@ const int lastditch; load_result = tzload(TZDEFRULES, sp, FALSE); if (load_result != 0) sp->leapcnt = 0; /* so, we're off a little */ - sp->timecnt = 0; if (*name != '\0') { if (*name == '<') { dstname = ++name; @@ -1044,6 +1014,7 @@ const int lastditch; /* ** Two transitions per year, from EPOCH_YEAR forward. */ + sp->ttis[0] = sp->ttis[1] = zttinfo; sp->ttis[0].tt_gmtoff = -dstoffset; sp->ttis[0].tt_isdst = 1; sp->ttis[0].tt_abbrind = stdlen + 1; @@ -1053,6 +1024,7 @@ const int lastditch; atp = sp->ats; typep = sp->types; janfirst = 0; + sp->timecnt = 0; for (year = EPOCH_YEAR; sp->timecnt + 2 <= TZ_MAX_TIMES; ++year) { @@ -1082,9 +1054,9 @@ const int lastditch; janfirst = newfirst; } } else { - register long theirstdoffset; - register long theirdstoffset; - register long theiroffset; + register int_fast32_t theirstdoffset; + register int_fast32_t theirdstoffset; + register int_fast32_t theiroffset; register int isdst; register int i; register int j; @@ -1156,8 +1128,8 @@ const int lastditch; } /* ** Finally, fill in ttis. - ** ttisstd and ttisgmt need not be handled. */ + sp->ttis[0] = sp->ttis[1] = zttinfo; sp->ttis[0].tt_gmtoff = -stdoffset; sp->ttis[0].tt_isdst = FALSE; sp->ttis[0].tt_abbrind = 0; @@ -1170,6 +1142,7 @@ const int lastditch; dstlen = 0; sp->typecnt = 1; /* only standard time */ sp->timecnt = 0; + sp->ttis[0] = zttinfo; sp->ttis[0].tt_gmtoff = -stdoffset; sp->ttis[0].tt_isdst = 0; sp->ttis[0].tt_abbrind = 0; @@ -1191,15 +1164,21 @@ const int lastditch; } static void -gmtload(sp) -struct state * const sp; +gmtload(struct state * const sp) { if (tzload(gmt, sp, TRUE) != 0) (void) tzparse(gmt, sp, TRUE); } -static void -tzsetwall P((void)) +#ifndef STD_INSPIRED +/* +** A non-static declaration of tzsetwall in a system header file +** may cause a warning about this upcoming static declaration... +*/ +static +#endif /* !defined STD_INSPIRED */ +void +tzsetwall(void) { if (lcl_is_set < 0) return; @@ -1207,29 +1186,32 @@ tzsetwall P((void)) #ifdef ALL_STATE if (lclptr == NULL) { - lclptr = (struct state *) malloc(sizeof *lclptr); + lclptr = calloc(1, sizeof *lclptr); if (lclptr == NULL) { settzname(); /* all we can do */ return; } } #endif /* defined ALL_STATE */ - if (tzload((char *) NULL, lclptr, TRUE) != 0) + if (tzload(NULL, lclptr, TRUE) != 0) gmtload(lclptr); settzname(); } +#include <sys/system_properties.h> // For __system_property_get. + static void -tzset_locked P((void)) +tzset_locked(void) { register const char * name = NULL; - static char buf[PROP_VALUE_MAX]; name = getenv("TZ"); // try the "persist.sys.timezone" system property first - if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0) + static char buf[PROP_VALUE_MAX]; + if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0) { name = buf; + } if (name == NULL) { tzsetwall(); @@ -1244,7 +1226,7 @@ tzset_locked P((void)) #ifdef ALL_STATE if (lclptr == NULL) { - lclptr = (struct state *) malloc(sizeof *lclptr); + lclptr = calloc(1, sizeof *lclptr); if (lclptr == NULL) { settzname(); /* all we can do */ return; @@ -1269,7 +1251,7 @@ tzset_locked P((void)) } void -tzset P((void)) +tzset(void) { _tzLock(); tzset_locked(); @@ -1287,11 +1269,8 @@ tzset P((void)) /*ARGSUSED*/ static struct tm * -localsub(timep, offset, tmp, sp) // android-changed: added sp. -const time_t * const timep; -const long offset; -struct tm * const tmp; -const struct state * sp; // android-added: added sp. +localsub(const time_t * const timep, const int_fast32_t offset, + struct tm * const tmp, const struct state * sp) // android-changed: added sp. { register const struct ttinfo * ttisp; register int i; @@ -1347,12 +1326,7 @@ const struct state * sp; // android-added: added sp. return result; } if (sp->timecnt == 0 || t < sp->ats[0]) { - i = 0; - while (sp->ttis[i].tt_isdst) - if (++i >= sp->typecnt) { - i = 0; - break; - } + i = sp->defaulttype; } else { register int lo = 1; register int hi = sp->timecnt; @@ -1383,8 +1357,7 @@ const struct state * sp; // android-added: added sp. } struct tm * -localtime(timep) -const time_t * const timep; +localtime(const time_t * const timep) { return localtime_r(timep, &tmGlobal); } @@ -1394,9 +1367,7 @@ const time_t * const timep; */ struct tm * -localtime_r(timep, tmp) -const time_t * const timep; -struct tm * tmp; +localtime_r(const time_t * const timep, struct tm * tmp) { struct tm* result; @@ -1413,11 +1384,8 @@ struct tm * tmp; */ static struct tm * -gmtsub(timep, offset, tmp, sp) // android-changed: added sp. -const time_t * const timep; -const long offset; -struct tm * const tmp; -const struct state * sp; // android-changed: added sp. +gmtsub(const time_t * const timep, const int_fast32_t offset, + struct tm *const tmp, const struct state * sp) // android-changed: added sp. { register struct tm * result; @@ -1426,7 +1394,7 @@ const struct state * sp; // android-changed: added sp. if (!gmt_is_set) { gmt_is_set = TRUE; #ifdef ALL_STATE - gmtptr = (struct state *) malloc(sizeof *gmtptr); + gmtptr = calloc(1, sizeof *gmtptr); if (gmtptr != NULL) #endif /* defined ALL_STATE */ gmtload(gmtptr); @@ -1455,8 +1423,7 @@ const struct state * sp; // android-changed: added sp. } struct tm * -gmtime(timep) -const time_t * const timep; +gmtime(const time_t * const timep) { return gmtime_r(timep, &tmGlobal); } @@ -1466,9 +1433,7 @@ const time_t * const timep; */ struct tm * -gmtime_r(timep, tmp) -const time_t * const timep; -struct tm * tmp; +gmtime_r(const time_t * const timep, struct tm * tmp) { struct tm* result; @@ -1479,45 +1444,30 @@ struct tm * tmp; return result; } -#ifdef STD_INSPIRED -#if 0 /* disabled because there is no good documentation for this function */ -struct tm * -offtime(timep, offset) -const time_t * const timep; -const long offset; -{ - return gmtsub(timep, offset, &tmGlobal, NULL); // android-changed: extra parameter. -} -#endif /* 0 */ -#endif /* defined STD_INSPIRED */ - /* ** Return the number of leap years through the end of the given year ** where, to make the math easy, the answer for year zero is defined as zero. */ static int -leaps_thru_end_of(y) -register const int y; +leaps_thru_end_of(register const int y) { return (y >= 0) ? (y / 4 - y / 100 + y / 400) : -(leaps_thru_end_of(-(y + 1)) + 1); } static struct tm * -timesub(timep, offset, sp, tmp) -const time_t * const timep; -const long offset; -register const struct state * const sp; -register struct tm * const tmp; +timesub(const time_t *const timep, const int_fast32_t offset, + register const struct state *const sp, + register struct tm *const tmp) { register const struct lsinfo * lp; register time_t tdays; register int idays; /* unsigned would be so 2003 */ - register long rem; + register int_fast64_t rem; int y; register const int * ip; - register long corr; + register int_fast64_t corr; register int hit; register int i; @@ -1574,9 +1524,10 @@ register struct tm * const tmp; y = newy; } { - register long seconds; + register int_fast32_t seconds; + register time_t half_second = 0.5; - seconds = tdays * SECSPERDAY + 0.5; + seconds = tdays * SECSPERDAY + half_second; tdays = seconds / SECSPERDAY; rem += seconds - tdays * SECSPERDAY; } @@ -1639,8 +1590,7 @@ register struct tm * const tmp; } char * -ctime(timep) -const time_t * const timep; +ctime(const time_t * const timep) { /* ** Section 4.12.3.2 of X3.159-1989 requires that @@ -1652,9 +1602,7 @@ const time_t * const timep; } char * -ctime_r(timep, buf) -const time_t * const timep; -char * buf; +ctime_r(const time_t * const timep, char * buf) { struct tm mytm; @@ -1675,77 +1623,65 @@ char * buf; #endif /* !defined WRONG */ /* -** Simplified normalize logic courtesy Paul Eggert. +** Normalize logic courtesy Paul Eggert. */ static int -increment_overflow(number, delta) -int * number; -int delta; +increment_overflow(int *const ip, int j) { - unsigned number0 = (unsigned)*number; - unsigned number1 = (unsigned)(number0 + delta); - - *number = (int)number1; - - if (delta >= 0) { - return ((int)number1 < (int)number0); - } else { - return ((int)number1 > (int)number0); - } + register int const i = *ip; + + /* + ** If i >= 0 there can only be overflow if i + j > INT_MAX + ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow. + ** If i < 0 there can only be overflow if i + j < INT_MIN + ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow. + */ + if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i)) + return TRUE; + *ip += j; + return FALSE; } static int -long_increment_overflow(number, delta) -long * number; -int delta; +increment_overflow32(int_fast32_t *const lp, int const m) { - unsigned long number0 = (unsigned long)*number; - unsigned long number1 = (unsigned long)(number0 + delta); - - *number = (long)number1; + register int_fast32_t const l = *lp; - if (delta >= 0) { - return ((long)number1 < (long)number0); - } else { - return ((long)number1 > (long)number0); - } + if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l)) + return TRUE; + *lp += m; + return FALSE; } static int -normalize_overflow(tensptr, unitsptr, base) -int * const tensptr; -int * const unitsptr; -const int base; +normalize_overflow(int *const tensptr, int *const unitsptr, const int base) { - register int tensdelta; + register int tensdelta; - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return increment_overflow(tensptr, tensdelta); + tensdelta = (*unitsptr >= 0) ? + (*unitsptr / base) : + (-1 - (-1 - *unitsptr) / base); + *unitsptr -= tensdelta * base; + return increment_overflow(tensptr, tensdelta); } static int -long_normalize_overflow(tensptr, unitsptr, base) -long * const tensptr; -int * const unitsptr; -const int base; +normalize_overflow32(int_fast32_t *const tensptr, int *const unitsptr, + const int base) { - register int tensdelta; + register int tensdelta; - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return long_increment_overflow(tensptr, tensdelta); + tensdelta = (*unitsptr >= 0) ? + (*unitsptr / base) : + (-1 - (-1 - *unitsptr) / base); + *unitsptr -= tensdelta * base; + return increment_overflow32(tensptr, tensdelta); } static int -tmcomp(atmp, btmp) -register const struct tm * const atmp; -register const struct tm * const btmp; +tmcomp(register const struct tm * const atmp, + register const struct tm * const btmp) { register int result; @@ -1759,21 +1695,19 @@ register const struct tm * const btmp; } static time_t -time2sub(tmp, funcp, offset, okayp, do_norm_secs, sp) // android-changed: added sp -struct tm * const tmp; -struct tm * (* const funcp) P((const time_t*, long, struct tm*, const struct state*)); // android-changed: added state* -const long offset; -int * const okayp; -const int do_norm_secs; -const struct state * sp; // android-changed: added sp +time2sub(struct tm * const tmp, + struct tm *(*const funcp)(const time_t*, int_fast32_t, struct tm*, const struct state*), + const int_fast32_t offset, + int * const okayp, + const int do_norm_secs, const struct state * sp) // android-changed: added sp { register int dir; register int i, j; register int saved_seconds; - register long li; + register int_fast32_t li; register time_t lo; register time_t hi; - long y; + int_fast32_t y; time_t newt; time_t t; struct tm yourtm, mytm; @@ -1790,16 +1724,16 @@ const struct state * sp; // android-changed: added sp if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) return WRONG; y = yourtm.tm_year; - if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR)) + if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR)) return WRONG; /* ** Turn y into an actual year number for now. ** It is converted back to an offset from TM_YEAR_BASE later. */ - if (long_increment_overflow(&y, TM_YEAR_BASE)) + if (increment_overflow32(&y, TM_YEAR_BASE)) return WRONG; while (yourtm.tm_mday <= 0) { - if (long_increment_overflow(&y, -1)) + if (increment_overflow32(&y, -1)) return WRONG; li = y + (1 < yourtm.tm_mon); yourtm.tm_mday += year_lengths[isleap(li)]; @@ -1807,7 +1741,7 @@ const struct state * sp; // android-changed: added sp while (yourtm.tm_mday > DAYSPERLYEAR) { li = y + (1 < yourtm.tm_mon); yourtm.tm_mday -= year_lengths[isleap(li)]; - if (long_increment_overflow(&y, 1)) + if (increment_overflow32(&y, 1)) return WRONG; } for ( ; ; ) { @@ -1817,11 +1751,11 @@ const struct state * sp; // android-changed: added sp yourtm.tm_mday -= i; if (++yourtm.tm_mon >= MONSPERYEAR) { yourtm.tm_mon = 0; - if (long_increment_overflow(&y, 1)) + if (increment_overflow32(&y, 1)) return WRONG; } } - if (long_increment_overflow(&y, -TM_YEAR_BASE)) + if (increment_overflow32(&y, -TM_YEAR_BASE)) return WRONG; yourtm.tm_year = y; if (yourtm.tm_year != y) @@ -1878,14 +1812,14 @@ const struct state * sp; // android-changed: added sp } else dir = tmcomp(&mytm, &yourtm); if (dir != 0) { if (t == lo) { - if (t == TIME_T_MAX) - return WRONG; ++t; + if (t <= lo) + return WRONG; ++lo; } else if (t == hi) { - if (t == TIME_T_MIN) - return WRONG; --t; + if (t >= hi) + return WRONG; --hi; } if (lo > hi) @@ -1903,14 +1837,10 @@ const struct state * sp; // android-changed: added sp ** It's okay to guess wrong since the guess ** gets checked. */ - /* - ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. - */ // BEGIN android-changed: support user-supplied sp if (sp == NULL) { sp = (const struct state *) - (((void *) funcp == (void *) localsub) ? - lclptr : gmtptr); + ((funcp == localsub) ? lclptr : gmtptr); } // END android-changed #ifdef ALL_STATE @@ -1950,14 +1880,11 @@ label: return t; } -// BEGIN android-changed: added sp. static time_t -time2(tmp, funcp, offset, okayp, sp) -struct tm * const tmp; -struct tm * (* const funcp) P((const time_t*, long, struct tm*, const struct state*)); -const long offset; -int * const okayp; -const struct state * sp; +time2(struct tm * const tmp, + struct tm * (*const funcp)(const time_t *, int_fast32_t, struct tm *, const struct state *), // android-changed: added sp. + const int_fast32_t offset, + int *const okayp, const struct state* sp) // android-changed: added sp. { time_t t; @@ -1969,14 +1896,11 @@ const struct state * sp; t = time2sub(tmp, funcp, offset, okayp, FALSE, sp); return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp); } -// END android-changed static time_t -time1(tmp, funcp, offset, sp) // android-changed: added sp. -struct tm * const tmp; -struct tm * (* const funcp) P((const time_t *, long, struct tm *, const struct state *)); -const long offset; -const struct state * sp; // android-changed: added sp. +time1(struct tm * const tmp, + struct tm * (* const funcp) (const time_t *, int_fast32_t, struct tm *, const struct state *), // android-changed: added sp. + const int_fast32_t offset, const struct state * sp) // android-changed: added sp. { register time_t t; register int samei, otheri; @@ -1987,6 +1911,10 @@ const struct state * sp; // android-changed: added sp. int types[TZ_MAX_TYPES]; int okay; + if (tmp == NULL) { + errno = EINVAL; + return WRONG; + } if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp. @@ -2009,13 +1937,9 @@ const struct state * sp; // android-changed: added sp. ** We try to divine the type they started from and adjust to the ** type they need. */ - /* - ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. - */ // BEGIN android-changed: support user-supplied sp. if (sp == NULL) { - sp = (const struct state *) (((void *) funcp == (void *) localsub) ? - lclptr : gmtptr); + sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr); } // BEGIN android-changed #ifdef ALL_STATE @@ -2053,86 +1977,32 @@ const struct state * sp; // android-changed: added sp. } time_t -mktime(tmp) -struct tm * const tmp; +mktime(struct tm * const tmp) { - time_t result; _tzLock(); tzset_locked(); - result = time1(tmp, localsub, 0L, NULL); // android-changed: extra parameter. + time_t result = time1(tmp, localsub, 0L, NULL); // android-changed: extra parameter. _tzUnlock(); return result; } -// BEGIN android-added - -// Caches the most recent timezone (http://b/8270865). -static int __bionic_tzload_cached(const char* name, struct state* const sp, const int doextend) { - _tzLock(); - - // Our single-item cache. - static char* gCachedTimeZoneName; - static struct state gCachedTimeZone; - - // Do we already have this timezone cached? - if (gCachedTimeZoneName != NULL && strcmp(name, gCachedTimeZoneName) == 0) { - *sp = gCachedTimeZone; - _tzUnlock(); - return 0; - } - - // Can we load it? - int rc = tzload(name, sp, doextend); - if (rc == 0) { - // Update the cache. - free(gCachedTimeZoneName); - gCachedTimeZoneName = strdup(name); - gCachedTimeZone = *sp; - } - - _tzUnlock(); - return rc; -} - -// Non-standard API: mktime(3) but with an explicit timezone parameter. -time_t mktime_tz(struct tm* const tmp, const char* tz) { - struct state st; - if (__bionic_tzload_cached(tz, &st, TRUE) != 0) { - // TODO: not sure what's best here, but for now, we fall back to gmt. - gmtload(&st); - } - return time1(tmp, localsub, 0L, &st); -} - -// Non-standard API: localtime(3) but with an explicit timezone parameter. -void localtime_tz(const time_t* const timep, struct tm* tmp, const char* tz) { - struct state st; - if (__bionic_tzload_cached(tz, &st, TRUE) != 0) { - // TODO: not sure what's best here, but for now, we fall back to gmt. - gmtload(&st); - } - localsub(timep, 0L, tmp, &st); -} - -// END android-added - #ifdef STD_INSPIRED time_t -timelocal(tmp) -struct tm * const tmp; +timelocal(struct tm * const tmp) { - tmp->tm_isdst = -1; /* in case it wasn't initialized */ + if (tmp != NULL) + tmp->tm_isdst = -1; /* in case it wasn't initialized */ return mktime(tmp); } time_t -timegm(tmp) -struct tm * const tmp; +timegm(struct tm * const tmp) { time_t result; - tmp->tm_isdst = 0; + if (tmp != NULL) + tmp->tm_isdst = 0; _tzLock(); result = time1(tmp, gmtsub, 0L, NULL); // android-changed: extra parameter. _tzUnlock(); @@ -2140,23 +2010,6 @@ struct tm * const tmp; return result; } -#if 0 /* disable due to lack of clear documentation on this function */ -time_t -timeoff(tmp, offset) -struct tm * const tmp; -const long offset; -{ - time_t result; - - tmp->tm_isdst = 0; - _tzLock(); - result = time1(tmp, gmtsub, offset, NULL); // android-changed: extra parameter. - _tzUnlock(); - - return result; -} -#endif /* 0 */ - #endif /* defined STD_INSPIRED */ #ifdef CMUCS @@ -2166,9 +2019,8 @@ const long offset; ** previous versions of the CMUCS runtime library. */ -long -gtime(tmp) -struct tm * const tmp; +int_fast32_t +gtime(struct tm * const tmp) { const time_t t = mktime(tmp); @@ -2193,9 +2045,8 @@ struct tm * const tmp; ** when exchanging timestamps with POSIX conforming systems. */ -static long -leapcorr(timep) -time_t * timep; +static int_fast64_t +leapcorr(time_t * timep) { register struct state * sp; register struct lsinfo * lp; @@ -2212,16 +2063,14 @@ time_t * timep; } time_t -time2posix(t) -time_t t; +time2posix(time_t t) { tzset(); return t - leapcorr(&t); } time_t -posix2time(t) -time_t t; +posix2time(time_t t) { time_t x; time_t y; @@ -2255,10 +2104,16 @@ time_t t; #endif /* defined STD_INSPIRED */ +// BEGIN android-added + #include <assert.h> #include <stdint.h> #include <arpa/inet.h> // For ntohl(3). +static int to_int(unsigned char* s) { + return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; +} + static int __bionic_open_tzdata_path(const char* path, const char* olson_id, int* data_size) { int fd = TEMP_FAILURE_RETRY(open(path, OPEN_MODE)); if (fd == -1) { @@ -2322,8 +2177,8 @@ static int __bionic_open_tzdata_path(const char* path, const char* olson_id, int this_id[NAME_LENGTH] = '\0'; if (strcmp(this_id, olson_id) == 0) { - specific_zone_offset = toint(buf + NAME_LENGTH) + ntohl(header.data_offset); - *data_size = toint(buf + NAME_LENGTH + sizeof(int32_t)); + specific_zone_offset = to_int(buf + NAME_LENGTH) + ntohl(header.data_offset); + *data_size = to_int(buf + NAME_LENGTH + sizeof(int32_t)); break; } } @@ -2359,3 +2214,53 @@ static int __bionic_open_tzdata(const char* olson_id, int* data_size) { } return fd; } + +// Caches the most recent timezone (http://b/8270865). +static int __bionic_tzload_cached(const char* name, struct state* const sp, const int doextend) { + _tzLock(); + + // Our single-item cache. + static char* gCachedTimeZoneName; + static struct state gCachedTimeZone; + + // Do we already have this timezone cached? + if (gCachedTimeZoneName != NULL && strcmp(name, gCachedTimeZoneName) == 0) { + *sp = gCachedTimeZone; + _tzUnlock(); + return 0; + } + + // Can we load it? + int rc = tzload(name, sp, doextend); + if (rc == 0) { + // Update the cache. + free(gCachedTimeZoneName); + gCachedTimeZoneName = strdup(name); + gCachedTimeZone = *sp; + } + + _tzUnlock(); + return rc; +} + +// Non-standard API: mktime(3) but with an explicit timezone parameter. +time_t mktime_tz(struct tm* const tmp, const char* tz) { + struct state st; + if (__bionic_tzload_cached(tz, &st, TRUE) != 0) { + // TODO: not sure what's best here, but for now, we fall back to gmt. + gmtload(&st); + } + return time1(tmp, localsub, 0L, &st); +} + +// Non-standard API: localtime(3) but with an explicit timezone parameter. +void localtime_tz(const time_t* const timep, struct tm* tmp, const char* tz) { + struct state st; + if (__bionic_tzload_cached(tz, &st, TRUE) != 0) { + // TODO: not sure what's best here, but for now, we fall back to gmt. + gmtload(&st); + } + localsub(timep, 0L, tmp, &st); +} + +// END android-added diff --git a/libc/tzcode/private.h b/libc/tzcode/private.h index e82a655..a31a26e 100644 --- a/libc/tzcode/private.h +++ b/libc/tzcode/private.h @@ -15,17 +15,7 @@ ** Thank you! */ -/* -** ID -*/ - -#ifndef lint -#ifndef NOID -static char privatehid[] = "@(#)private.h 8.2"; -#endif /* !defined NOID */ -#endif /* !defined lint */ - -#define GRANDPARENTED "Local time zone must be set--see zic manual page" +#define GRANDPARENTED "Local time zone must be set--see zic manual page" /* ** Defaults for preprocessor symbols. @@ -33,45 +23,45 @@ static char privatehid[] = "@(#)private.h 8.2"; */ #ifndef HAVE_ADJTIME -#define HAVE_ADJTIME 1 +#define HAVE_ADJTIME 1 #endif /* !defined HAVE_ADJTIME */ #ifndef HAVE_GETTEXT -#define HAVE_GETTEXT 0 +#define HAVE_GETTEXT 0 #endif /* !defined HAVE_GETTEXT */ #ifndef HAVE_INCOMPATIBLE_CTIME_R -#define HAVE_INCOMPATIBLE_CTIME_R 0 +#define HAVE_INCOMPATIBLE_CTIME_R 0 #endif /* !defined INCOMPATIBLE_CTIME_R */ #ifndef HAVE_SETTIMEOFDAY -#define HAVE_SETTIMEOFDAY 3 +#define HAVE_SETTIMEOFDAY 3 #endif /* !defined HAVE_SETTIMEOFDAY */ -#ifndef HAVE_STRERROR -#define HAVE_STRERROR 1 -#endif /* !defined HAVE_STRERROR */ - #ifndef HAVE_SYMLINK -#define HAVE_SYMLINK 1 +#define HAVE_SYMLINK 1 #endif /* !defined HAVE_SYMLINK */ #ifndef HAVE_SYS_STAT_H -#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_STAT_H 1 #endif /* !defined HAVE_SYS_STAT_H */ #ifndef HAVE_SYS_WAIT_H -#define HAVE_SYS_WAIT_H 1 +#define HAVE_SYS_WAIT_H 1 #endif /* !defined HAVE_SYS_WAIT_H */ #ifndef HAVE_UNISTD_H -#define HAVE_UNISTD_H 1 +#define HAVE_UNISTD_H 1 #endif /* !defined HAVE_UNISTD_H */ #ifndef HAVE_UTMPX_H -#define HAVE_UTMPX_H 0 +#define HAVE_UTMPX_H 0 #endif /* !defined HAVE_UTMPX_H */ +#ifndef LOCALE_HOME +#define LOCALE_HOME "/usr/lib/locale" +#endif /* !defined LOCALE_HOME */ + #if HAVE_INCOMPATIBLE_CTIME_R #define asctime_r _incompatible_asctime_r #define ctime_r _incompatible_ctime_r @@ -81,11 +71,11 @@ static char privatehid[] = "@(#)private.h 8.2"; ** Nested includes */ -#include "sys/types.h" /* for time_t */ +#include "sys/types.h" /* for time_t */ #include "stdio.h" #include "errno.h" #include "string.h" -#include "limits.h" /* for CHAR_BIT et al. */ +#include "limits.h" /* for CHAR_BIT et al. */ #include "time.h" #include "stdlib.h" @@ -94,28 +84,26 @@ static char privatehid[] = "@(#)private.h 8.2"; #endif /* HAVE_GETTEXT */ #if HAVE_SYS_WAIT_H -#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */ +#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */ #endif /* HAVE_SYS_WAIT_H */ #ifndef WIFEXITED -#define WIFEXITED(status) (((status) & 0xff) == 0) +#define WIFEXITED(status) (((status) & 0xff) == 0) #endif /* !defined WIFEXITED */ #ifndef WEXITSTATUS -#define WEXITSTATUS(status) (((status) >> 8) & 0xff) +#define WEXITSTATUS(status) (((status) >> 8) & 0xff) #endif /* !defined WEXITSTATUS */ #if HAVE_UNISTD_H -#include "unistd.h" /* for F_OK and R_OK */ +#include "unistd.h" /* for F_OK, R_OK, and other POSIX goodness */ #endif /* HAVE_UNISTD_H */ -#if !HAVE_UNISTD_H #ifndef F_OK -#define F_OK 0 +#define F_OK 0 #endif /* !defined F_OK */ #ifndef R_OK -#define R_OK 4 +#define R_OK 4 #endif /* !defined R_OK */ -#endif /* !HAVE_UNISTD_H */ /* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */ #define is_digit(c) ((unsigned)(c) - '0' <= 9) @@ -128,27 +116,73 @@ static char privatehid[] = "@(#)private.h 8.2"; */ #ifndef HAVE_STDINT_H #define HAVE_STDINT_H \ - (199901 <= __STDC_VERSION__ || \ - 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__))) + (199901 <= __STDC_VERSION__ || \ + 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__))) #endif /* !defined HAVE_STDINT_H */ #if HAVE_STDINT_H #include "stdint.h" #endif /* !HAVE_STDINT_H */ +#ifndef HAVE_INTTYPES_H +# define HAVE_INTTYPES_H HAVE_STDINT_H +#endif +#if HAVE_INTTYPES_H +# include <inttypes.h> +#endif + #ifndef INT_FAST64_MAX /* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */ #if defined LLONG_MAX || defined __LONG_LONG_MAX__ -typedef long long int_fast64_t; +typedef long long int_fast64_t; +# ifdef LLONG_MAX +# define INT_FAST64_MIN LLONG_MIN +# define INT_FAST64_MAX LLONG_MAX +# else +# define INT_FAST64_MIN __LONG_LONG_MIN__ +# define INT_FAST64_MAX __LONG_LONG_MAX__ +# endif +# define SCNdFAST64 "lld" #else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */ #if (LONG_MAX >> 31) < 0xffffffff Please use a compiler that supports a 64-bit integer type (or wider); you may need to compile with "-DHAVE_STDINT_H". #endif /* (LONG_MAX >> 31) < 0xffffffff */ -typedef long int_fast64_t; +typedef long int_fast64_t; +# define INT_FAST64_MIN LONG_MIN +# define INT_FAST64_MAX LONG_MAX +# define SCNdFAST64 "ld" #endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */ #endif /* !defined INT_FAST64_MAX */ +#ifndef INT_FAST32_MAX +# if INT_MAX >> 31 == 0 +typedef long int_fast32_t; +# else +typedef int int_fast32_t; +# endif +#endif + +#ifndef INTMAX_MAX +# if defined LLONG_MAX || defined __LONG_LONG_MAX__ +typedef long long intmax_t; +# define PRIdMAX "lld" +# else +typedef long intmax_t; +# define PRIdMAX "ld" +# endif +#endif + +#ifndef UINTMAX_MAX +# if defined ULLONG_MAX || defined __LONG_LONG_MAX__ +typedef unsigned long long uintmax_t; +# define PRIuMAX "llu" +# else +typedef unsigned long uintmax_t; +# define PRIuMAX "lu" +# endif +#endif + #ifndef INT32_MAX #define INT32_MAX 0x7fffffff #endif /* !defined INT32_MAX */ @@ -156,74 +190,30 @@ typedef long int_fast64_t; #define INT32_MIN (-1 - INT32_MAX) #endif /* !defined INT32_MIN */ -/* -** Workarounds for compilers/systems. -*/ - -/* -** If your compiler lacks prototypes, "#define P(x) ()". -*/ - -#ifndef P -#define P(x) x -#endif /* !defined P */ - -/* -** SunOS 4.1.1 headers lack EXIT_SUCCESS. -*/ - -#ifndef EXIT_SUCCESS -#define EXIT_SUCCESS 0 -#endif /* !defined EXIT_SUCCESS */ - -/* -** SunOS 4.1.1 headers lack EXIT_FAILURE. -*/ - -#ifndef EXIT_FAILURE -#define EXIT_FAILURE 1 -#endif /* !defined EXIT_FAILURE */ - -/* -** SunOS 4.1.1 headers lack FILENAME_MAX. -*/ - -#ifndef FILENAME_MAX - -#ifndef MAXPATHLEN -#ifdef unix -#include "sys/param.h" -#endif /* defined unix */ -#endif /* !defined MAXPATHLEN */ - -#ifdef MAXPATHLEN -#define FILENAME_MAX MAXPATHLEN -#endif /* defined MAXPATHLEN */ -#ifndef MAXPATHLEN -#define FILENAME_MAX 1024 /* Pure guesswork */ -#endif /* !defined MAXPATHLEN */ - -#endif /* !defined FILENAME_MAX */ +#if 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define ATTRIBUTE_CONST __attribute__ ((const)) +# define ATTRIBUTE_PURE __attribute__ ((__pure__)) +#else +# define ATTRIBUTE_CONST /* empty */ +# define ATTRIBUTE_PURE /* empty */ +#endif -/* -** SunOS 4.1.1 libraries lack remove. -*/ +#if !defined _Noreturn && __STDC_VERSION__ < 201112 +# if 2 < __GNUC__ + (8 <= __GNUC_MINOR__) +# define _Noreturn __attribute__ ((__noreturn__)) +# else +# define _Noreturn +# endif +#endif -#ifndef remove -extern int unlink P((const char * filename)); -#define remove unlink -#endif /* !defined remove */ +#if __STDC_VERSION__ < 199901 && !defined restrict +# define restrict /* empty */ +#endif /* -** Some ancient errno.h implementations don't declare errno. -** But some newer errno.h implementations define it as a macro. -** Fix the former without affecting the latter. +** Workarounds for compilers/systems. */ -#ifndef errno -extern int errno; -#endif /* !defined errno */ - /* ** Some time.h implementations don't declare asctime_r. ** Others might define it as a macro. @@ -231,36 +221,83 @@ extern int errno; */ #ifndef asctime_r -extern char * asctime_r(); +extern char * asctime_r(struct tm const *, char *); +#endif + +/* +** Compile with -Dtime_tz=T to build the tz package with a private +** time_t type equivalent to T rather than the system-supplied time_t. +** This debugging feature can test unusual design decisions +** (e.g., time_t wider than 'long', or unsigned time_t) even on +** typical platforms. +*/ +#ifdef time_tz +static time_t sys_time(time_t *x) { return time(x); } + +# undef ctime +# define ctime tz_ctime +# undef ctime_r +# define ctime_r tz_ctime_r +# undef difftime +# define difftime tz_difftime +# undef gmtime +# define gmtime tz_gmtime +# undef gmtime_r +# define gmtime_r tz_gmtime_r +# undef localtime +# define localtime tz_localtime +# undef localtime_r +# define localtime_r tz_localtime_r +# undef mktime +# define mktime tz_mktime +# undef time +# define time tz_time +# undef time_t +# define time_t tz_time_t + +typedef time_tz time_t; + +char *ctime(time_t const *); +char *ctime_r(time_t const *, char *); +double difftime(time_t, time_t); +struct tm *gmtime(time_t const *); +struct tm *gmtime_r(time_t const *restrict, struct tm *restrict); +struct tm *localtime(time_t const *); +struct tm *localtime_r(time_t const *restrict, struct tm *restrict); +time_t mktime(struct tm *); + +static time_t +time(time_t *p) +{ + time_t r = sys_time(0); + if (p) + *p = r; + return r; +} #endif /* ** Private function declarations. */ -char * icalloc P((int nelem, int elsize)); -char * icatalloc P((char * old, const char * new)); -char * icpyalloc P((const char * string)); -char * imalloc P((int n)); -void * irealloc P((void * pointer, int size)); -void icfree P((char * pointer)); -void ifree P((char * pointer)); -const char * scheck P((const char * string, const char * format)); +char * icatalloc(char * old, const char * new); +char * icpyalloc(const char * string); +const char * scheck(const char * string, const char * format); /* ** Finally, some convenience items. */ #ifndef TRUE -#define TRUE 1 +#define TRUE 1 #endif /* !defined TRUE */ #ifndef FALSE -#define FALSE 0 +#define FALSE 0 #endif /* !defined FALSE */ #ifndef TYPE_BIT -#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) +#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) #endif /* !defined TYPE_BIT */ #ifndef TYPE_SIGNED @@ -284,8 +321,8 @@ const char * scheck P((const char * string, const char * format)); ** add one more for a minus sign if the type is signed. */ #define INT_STRLEN_MAXIMUM(type) \ - ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \ - 1 + TYPE_SIGNED(type)) + ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \ + 1 + TYPE_SIGNED(type)) #endif /* !defined INT_STRLEN_MAXIMUM */ /* @@ -305,7 +342,7 @@ const char * scheck P((const char * string, const char * format)); #ifndef INITIALIZE #ifdef GNUC_or_lint -#define INITIALIZE(x) ((x) = 0) +#define INITIALIZE(x) ((x) = 0) #endif /* defined GNUC_or_lint */ #ifndef GNUC_or_lint #define INITIALIZE(x) @@ -333,12 +370,12 @@ const char * scheck P((const char * string, const char * format)); #if HAVE_INCOMPATIBLE_CTIME_R #undef asctime_r #undef ctime_r -char *asctime_r P((struct tm const *, char *)); -char *ctime_r P((time_t const *, char *)); +char *asctime_r(struct tm const *, char *); +char *ctime_r(time_t const *, char *); #endif /* HAVE_INCOMPATIBLE_CTIME_R */ #ifndef YEARSPERREPEAT -#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */ +#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */ #endif /* !defined YEARSPERREPEAT */ /* @@ -346,15 +383,15 @@ char *ctime_r P((time_t const *, char *)); */ #ifndef AVGSECSPERYEAR -#define AVGSECSPERYEAR 31556952L +#define AVGSECSPERYEAR 31556952L #endif /* !defined AVGSECSPERYEAR */ #ifndef SECSPERREPEAT -#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR) +#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR) #endif /* !defined SECSPERREPEAT */ - + #ifndef SECSPERREPEAT_BITS -#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */ +#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */ #endif /* !defined SECSPERREPEAT_BITS */ /* diff --git a/libc/tzcode/strftime.c b/libc/tzcode/strftime.c index f6e7435..e92c44d 100644 --- a/libc/tzcode/strftime.c +++ b/libc/tzcode/strftime.c @@ -111,12 +111,12 @@ static const struct lc_time_T C_time_locale = { "%a %b %e %H:%M:%S %Z %Y" }; -static char * _add P((const char *, char *, const char *, int)); -static char * _conv P((int, const char *, char *, const char *)); -static char * _fmt P((const char *, const struct tm *, char *, const char *, - int *, const struct strftime_locale*)); -static char * _yconv P((int, int, int, int, char *, const char *, int)); -static char * getformat P((int, char *, char *, char *, char *)); +static char * _add(const char *, char *, const char *, int); +static char * _conv(int, const char *, char *, const char *); +static char * _fmt(const char *, const struct tm *, char *, const char *, + int *, const struct strftime_locale*); +static char * _yconv(int, int, int, int, char *, const char *, int); +static char * getformat(int, char *, char *, char *, char *); extern char * tzname[]; diff --git a/libc/tzcode/tzfile.h b/libc/tzcode/tzfile.h index f6c9a05..d04fe04 100644 --- a/libc/tzcode/tzfile.h +++ b/libc/tzcode/tzfile.h @@ -16,72 +16,62 @@ */ /* -** ID -*/ - -#ifndef lint -#ifndef NOID -static char tzfilehid[] = "@(#)tzfile.h 8.1"; -#endif /* !defined NOID */ -#endif /* !defined lint */ - -/* ** Information about time zone files. */ #ifndef TZDIR -#define TZDIR "/system/usr/share/zoneinfo" /* Time zone object file directory */ +#define TZDIR "/usr/local/etc/zoneinfo" /* Time zone object file directory */ #endif /* !defined TZDIR */ #ifndef TZDEFAULT -#define TZDEFAULT "localtime" +#define TZDEFAULT "localtime" #endif /* !defined TZDEFAULT */ #ifndef TZDEFRULES -#define TZDEFRULES "posixrules" +#define TZDEFRULES "posixrules" #endif /* !defined TZDEFRULES */ /* ** Each file begins with. . . */ -#define TZ_MAGIC "TZif" +#define TZ_MAGIC "TZif" struct tzhead { - char tzh_magic[4]; /* TZ_MAGIC */ - char tzh_version[1]; /* '\0' or '2' as of 2005 */ - char tzh_reserved[15]; /* reserved--must be zero */ - char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ - char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ - char tzh_leapcnt[4]; /* coded number of leap seconds */ - char tzh_timecnt[4]; /* coded number of transition times */ - char tzh_typecnt[4]; /* coded number of local time types */ - char tzh_charcnt[4]; /* coded number of abbr. chars */ + char tzh_magic[4]; /* TZ_MAGIC */ + char tzh_version[1]; /* '\0' or '2' as of 2005 */ + char tzh_reserved[15]; /* reserved--must be zero */ + char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ + char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ + char tzh_leapcnt[4]; /* coded number of leap seconds */ + char tzh_timecnt[4]; /* coded number of transition times */ + char tzh_typecnt[4]; /* coded number of local time types */ + char tzh_charcnt[4]; /* coded number of abbr. chars */ }; /* ** . . .followed by. . . ** -** tzh_timecnt (char [4])s coded transition times a la time(2) -** tzh_timecnt (unsigned char)s types of local time starting at above -** tzh_typecnt repetitions of -** one (char [4]) coded UTC offset in seconds -** one (unsigned char) used to set tm_isdst -** one (unsigned char) that's an abbreviation list index -** tzh_charcnt (char)s '\0'-terminated zone abbreviations -** tzh_leapcnt repetitions of -** one (char [4]) coded leap second transition times -** one (char [4]) total correction after above -** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition -** time is standard time, if FALSE, -** transition time is wall clock time -** if absent, transition times are -** assumed to be wall clock time -** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition -** time is UTC, if FALSE, -** transition time is local time -** if absent, transition times are -** assumed to be local time +** tzh_timecnt (char [4])s coded transition times a la time(2) +** tzh_timecnt (unsigned char)s types of local time starting at above +** tzh_typecnt repetitions of +** one (char [4]) coded UTC offset in seconds +** one (unsigned char) used to set tm_isdst +** one (unsigned char) that's an abbreviation list index +** tzh_charcnt (char)s '\0'-terminated zone abbreviations +** tzh_leapcnt repetitions of +** one (char [4]) coded leap second transition times +** one (char [4]) total correction after above +** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition +** time is standard time, if FALSE, +** transition time is wall clock time +** if absent, transition times are +** assumed to be wall clock time +** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition +** time is UTC, if FALSE, +** transition time is local time +** if absent, transition times are +** assumed to be local time */ /* @@ -100,81 +90,81 @@ struct tzhead { */ #ifndef TZ_MAX_TIMES -#define TZ_MAX_TIMES 1200 +#define TZ_MAX_TIMES 1200 #endif /* !defined TZ_MAX_TIMES */ #ifndef TZ_MAX_TYPES #ifndef NOSOLAR -#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ +#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ #endif /* !defined NOSOLAR */ #ifdef NOSOLAR /* ** Must be at least 14 for Europe/Riga as of Jan 12 1995, ** as noted by Earl Chew. */ -#define TZ_MAX_TYPES 20 /* Maximum number of local time types */ +#define TZ_MAX_TYPES 20 /* Maximum number of local time types */ #endif /* !defined NOSOLAR */ #endif /* !defined TZ_MAX_TYPES */ #ifndef TZ_MAX_CHARS -#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ - /* (limited by what unsigned chars can hold) */ +#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ + /* (limited by what unsigned chars can hold) */ #endif /* !defined TZ_MAX_CHARS */ #ifndef TZ_MAX_LEAPS -#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ +#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ #endif /* !defined TZ_MAX_LEAPS */ -#define SECSPERMIN 60 -#define MINSPERHOUR 60 -#define HOURSPERDAY 24 -#define DAYSPERWEEK 7 -#define DAYSPERNYEAR 365 -#define DAYSPERLYEAR 366 -#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) -#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY) -#define MONSPERYEAR 12 - -#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 SECSPERMIN 60 +#define MINSPERHOUR 60 +#define HOURSPERDAY 24 +#define DAYSPERWEEK 7 +#define DAYSPERNYEAR 365 +#define DAYSPERLYEAR 366 +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY) +#define MONSPERYEAR 12 + +#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)) /* ** Since everything in isleap is modulo 400 (or a factor of 400), we know that -** isleap(y) == isleap(y % 400) +** isleap(y) == isleap(y % 400) ** and so -** isleap(a + b) == isleap((a + b) % 400) +** isleap(a + b) == isleap((a + b) % 400) ** or -** isleap(a + b) == isleap(a % 400 + b % 400) +** isleap(a + b) == isleap(a % 400 + b % 400) ** This is true even if % means modulo rather than Fortran remainder ** (which is allowed by C89 but not C99). ** We use this to avoid addition overflow problems. */ -#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) +#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) #endif /* !defined TZFILE_H */ |