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
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 @@
#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 @@
# 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 @@
#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 @@
#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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
ttisp->tt_ttisgmt = *p++;
if (ttisp->tt_ttisgmt != TRUE &&
ttisp->tt_ttisgmt != FALSE)
- return -1;
+ goto oops;
}
}
/*
@@ -568,36 +472,47 @@
** 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 @@
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 @@
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 char *
-getzname(strp)
-register const char * strp;
+getzname(register const char * strp)
{
register char c;
@@ -705,11 +690,7 @@
*/
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 @@
*/
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 @@
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 @@
*/
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 @@
*/
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 @@
*/
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 @@
*/
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 @@
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 @@
/*
** 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 @@
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 @@
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 @@
}
/*
** 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 @@
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 @@
}
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 @@
#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 @@
#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 @@
}
void
-tzset P((void))
+tzset(void)
{
_tzLock();
tzset_locked();
@@ -1287,11 +1269,8 @@
/*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 @@
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 @@
}
struct tm *
-localtime(timep)
-const time_t * const timep;
+localtime(const time_t * const timep)
{
return localtime_r(timep, &tmGlobal);
}
@@ -1394,9 +1367,7 @@
*/
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 @@
*/
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 @@
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 @@
}
struct tm *
-gmtime(timep)
-const time_t * const timep;
+gmtime(const time_t * const timep)
{
return gmtime_r(timep, &tmGlobal);
}
@@ -1466,9 +1433,7 @@
*/
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
#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 @@
}
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 @@
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 @@
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 @@
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 @@
} 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 @@
** 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 @@
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 @@
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 @@
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 @@
** 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 @@
}
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 @@
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 @@
** 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 @@
** 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
-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 @@
#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 @@
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 @@
}
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