diff --git a/libc/Android.mk b/libc/Android.mk index 16b24de8b..0e93acd59 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -70,11 +70,6 @@ libc_common_src_files := \ string/strtok.c \ wchar/wcswidth.c \ wchar/wcsxfrm.c \ - tzcode/asctime.c \ - tzcode/difftime.c \ - tzcode/localtime.c \ - tzcode/strftime.c \ - tzcode/strptime.c \ bionic/arc4random.c \ bionic/atoi.c \ bionic/atol.c \ @@ -247,6 +242,13 @@ libc_bionic_src_files := \ bionic/wait.cpp \ bionic/wchar.cpp \ +libc_tzcode_src_files := \ + tzcode/asctime.c \ + tzcode/difftime.c \ + tzcode/localtime.c \ + tzcode/strftime.c \ + tzcode/strptime.c \ + libc_upstream_freebsd_src_files := \ upstream-freebsd/lib/libc/stdio/clrerr.c \ upstream-freebsd/lib/libc/stdio/fclose.c \ @@ -490,14 +492,6 @@ libc_common_cflags := \ -DLOG_ON_HEAP_ERROR \ -Wall -Wextra -# these macro definitions are required to implement the -# 'timezone' and 'daylight' global variables, as well as -# properly update the 'tm_gmtoff' field in 'struct tm'. -# -libc_common_cflags += \ - -DTM_GMTOFF=tm_gmtoff \ - -DUSG_COMPAT=1 - ifeq ($(strip $(DEBUG_BIONIC_LIBC)),true) libc_common_cflags += -DDEBUG endif @@ -707,6 +701,28 @@ LOCAL_SYSTEM_SHARED_LIBRARIES := include $(BUILD_STATIC_LIBRARY) +# ======================================================== +# libc_tzcode.a - upstream 'tzcode' code +# ======================================================== + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(libc_tzcode_src_files) +LOCAL_CFLAGS := \ + $(libc_common_cflags) \ + -std=gnu99 \ + -DSTD_INSPIRED=1 \ + -DTZDIR=\"/system/usr/share/zoneinfo\" \ + -DTM_GMTOFF=tm_gmtoff \ + -DUSG_COMPAT=1 +LOCAL_C_INCLUDES := $(libc_common_c_includes) +LOCAL_MODULE := libc_tzcode +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_SYSTEM_SHARED_LIBRARIES := + +include $(BUILD_STATIC_LIBRARY) + + # ======================================================== # libc_freebsd.a - upstream FreeBSD C library code # ======================================================== @@ -782,7 +798,12 @@ LOCAL_CFLAGS := $(libc_common_cflags) \ LOCAL_C_INCLUDES := $(libc_common_c_includes) LOCAL_MODULE := libc_common LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_WHOLE_STATIC_LIBRARIES := libbionic_ssp libc_bionic libc_freebsd libc_netbsd +LOCAL_WHOLE_STATIC_LIBRARIES := \ + libbionic_ssp \ + libc_bionic \ + libc_freebsd \ + libc_netbsd \ + libc_tzcode LOCAL_SYSTEM_SHARED_LIBRARIES := include $(BUILD_STATIC_LIBRARY) diff --git a/libc/tzcode/asctime.c b/libc/tzcode/asctime.c index 22bba34f7..152b0db4e 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 f7581a4a4..fcd18ceff 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 0c4d2683c..d1b49e5c0 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 - #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 +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,25 +285,14 @@ settzname P((void)) return; } #endif /* defined ALL_STATE */ - 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]; -#ifdef USG_COMPAT - if (ttisp->tt_isdst) - daylight = 1; - if (i == 0 || !ttisp->tt_isdst) - timezone = -(ttisp->tt_gmtoff); -#endif /* defined USG_COMPAT */ -#ifdef ALTZONE - if (i == 0 || ttisp->tt_isdst) - altzone = -(ttisp->tt_gmtoff); -#endif /* defined ALTZONE */ - } /* ** 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[ @@ -363,6 +300,16 @@ settzname P((void)) tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind]; +#ifdef USG_COMPAT + if (ttisp->tt_isdst) + daylight = 1; + if (!ttisp->tt_isdst) + timezone = -(ttisp->tt_gmtoff); +#endif /* defined USG_COMPAT */ +#ifdef ALTZONE + if (ttisp->tt_isdst) + altzone = -(ttisp->tt_gmtoff); +#endif /* defined ALTZONE */ } /* ** Finally, scrub the abbreviations. @@ -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; + } u_t; +#ifdef ALL_STATE + register u_t * up; - 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; + 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 */ - 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; - } - } + 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 (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; - for (j = 0; j + i < sp->timecnt; ++j) { - sp->ats[j] = sp->ats[j + i]; - sp->types[j] = sp->types[j + i]; + /* + ** 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 // 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); + register int const i = *ip; - *number = (int)number1; - - if (delta >= 0) { - return ((int)number1 < (int)number0); - } else { - return ((int)number1 > (int)number0); - } + /* + ** 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); + register int_fast32_t const l = *lp; - *number = (long)number1; - - 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 #include #include // 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 e82a65576..a31a26e16 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 /* for WIFEXITED and WEXITSTATUS */ +#include /* 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 '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 +#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 */ +#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 + +#if !defined _Noreturn && __STDC_VERSION__ < 201112 +# if 2 < __GNUC__ + (8 <= __GNUC_MINOR__) +# define _Noreturn __attribute__ ((__noreturn__)) +# else +# define _Noreturn +# endif +#endif + +#if __STDC_VERSION__ < 199901 && !defined restrict +# define restrict /* empty */ +#endif + /* ** 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 */ - -/* -** SunOS 4.1.1 libraries lack remove. -*/ - -#ifndef remove -extern int unlink P((const char * filename)); -#define remove unlink -#endif /* !defined remove */ - -/* -** 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. -*/ - -#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 f6e743575..e92c44d33 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 f6c9a05f7..d04fe0446 100644 --- a/libc/tzcode/tzfile.h +++ b/libc/tzcode/tzfile.h @@ -15,73 +15,63 @@ ** Thank you! */ -/* -** 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 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_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_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 TM_YEAR_BASE 1900 -#define EPOCH_YEAR 1970 -#define EPOCH_WDAY TM_THURSDAY +#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 */