blob: 3efa5dd4ad06ba35b0749619307f16c9cb4045db [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
2** This file is in the public domain, so clarified as of
3** 1996-06-05 by Arthur David Olson.
4*/
5
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08006/*
7** Leap second handling from Bradley White.
8** POSIX-style TZ environment variable handling from Guy Harris.
9*/
10
11/*LINTLIBRARY*/
12
13#include "private.h"
14#include "tzfile.h"
15#include "fcntl.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080016
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080017#ifndef TZ_ABBR_MAX_LEN
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070018#define TZ_ABBR_MAX_LEN 16
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080019#endif /* !defined TZ_ABBR_MAX_LEN */
20
21#ifndef TZ_ABBR_CHAR_SET
22#define TZ_ABBR_CHAR_SET \
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070023 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080024#endif /* !defined TZ_ABBR_CHAR_SET */
25
26#ifndef TZ_ABBR_ERR_CHAR
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070027#define TZ_ABBR_ERR_CHAR '_'
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080028#endif /* !defined TZ_ABBR_ERR_CHAR */
29
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080030/*
31** SunOS 4.1.1 headers lack O_BINARY.
32*/
33
34#ifdef O_BINARY
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070035#define OPEN_MODE (O_RDONLY | O_BINARY)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080036#endif /* defined O_BINARY */
37#ifndef O_BINARY
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070038#define OPEN_MODE O_RDONLY
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080039#endif /* !defined O_BINARY */
40
41#if 0
42# define XLOG(xx) printf xx , fflush(stdout)
43#else
44# define XLOG(x) do{}while (0)
45#endif
46
Elliott Hughesce4783c2013-07-12 17:31:11 -070047/* BEGIN android-added: thread-safety. */
48#include <pthread.h>
49static pthread_mutex_t _tzMutex = PTHREAD_MUTEX_INITIALIZER;
50static inline void _tzLock(void) { pthread_mutex_lock(&_tzMutex); }
51static inline void _tzUnlock(void) { pthread_mutex_unlock(&_tzMutex); }
52/* END android-added */
David 'Digit' Turner2093d352009-09-09 17:41:59 -070053
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080054#ifndef WILDABBR
55/*
56** Someone might make incorrect use of a time zone abbreviation:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070057** 1. They might reference tzname[0] before calling tzset (explicitly
58** or implicitly).
59** 2. They might reference tzname[1] before calling tzset (explicitly
60** or implicitly).
61** 3. They might reference tzname[1] after setting to a time zone
62** in which Daylight Saving Time is never observed.
63** 4. They might reference tzname[0] after setting to a time zone
64** in which Standard Time is never observed.
65** 5. They might reference tm.TM_ZONE after calling offtime.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080066** What's best to do in the above cases is open to debate;
67** for now, we just set things up so that in any of the five cases
68** WILDABBR is used. Another possibility: initialize tzname[0] to the
69** string "tzname[0] used before set", and similarly for the other cases.
70** And another: initialize tzname[0] to "ERA", with an explanation in the
71** manual page of what this "time zone abbreviation" means (doing this so
72** that tzname[0] has the "normal" length of three characters).
73*/
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070074#define WILDABBR " "
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080075#endif /* !defined WILDABBR */
76
Calin Juravled8928922014-02-28 12:18:53 +000077static char wildabbr[] = WILDABBR;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080078
Calin Juravled8928922014-02-28 12:18:53 +000079static const char gmt[] = "GMT";
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080080
81/*
82** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
83** We default to US rules as of 1999-08-17.
84** POSIX 1003.1 section 8.1.1 says that the default DST rules are
85** implementation dependent; for historical reasons, US rules are a
86** common default.
87*/
88#ifndef TZDEFRULESTRING
89#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
90#endif /* !defined TZDEFDST */
91
Calin Juravled8928922014-02-28 12:18:53 +000092struct ttinfo { /* time type information */
Elliott Hughese0d0b152013-09-27 00:04:30 -070093 int_fast32_t tt_gmtoff; /* UT offset in seconds */
Elliott Hughesce4783c2013-07-12 17:31:11 -070094 int tt_isdst; /* used to set tm_isdst */
95 int tt_abbrind; /* abbreviation list index */
96 int tt_ttisstd; /* TRUE if transition is std time */
Elliott Hughese0d0b152013-09-27 00:04:30 -070097 int tt_ttisgmt; /* TRUE if transition is UT */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080098};
99
Calin Juravled8928922014-02-28 12:18:53 +0000100struct lsinfo { /* leap second information */
Elliott Hughesce4783c2013-07-12 17:31:11 -0700101 time_t ls_trans; /* transition time */
102 int_fast64_t ls_corr; /* correction to apply */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800103};
104
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700105#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800106
107#ifdef TZNAME_MAX
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700108#define MY_TZNAME_MAX TZNAME_MAX
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800109#endif /* defined TZNAME_MAX */
110#ifndef TZNAME_MAX
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700111#define MY_TZNAME_MAX 255
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800112#endif /* !defined TZNAME_MAX */
113
114struct state {
Calin Juravled8928922014-02-28 12:18:53 +0000115 int leapcnt;
116 int timecnt;
117 int typecnt;
118 int charcnt;
119 int goback;
120 int goahead;
121 time_t ats[TZ_MAX_TIMES];
122 unsigned char types[TZ_MAX_TIMES];
123 struct ttinfo ttis[TZ_MAX_TYPES];
124 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
125 (2 * (MY_TZNAME_MAX + 1)))];
126 struct lsinfo lsis[TZ_MAX_LEAPS];
127 int defaulttype; /* for early times or if no transitions */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800128};
129
130struct rule {
Calin Juravled8928922014-02-28 12:18:53 +0000131 int r_type; /* type of rule--see below */
132 int r_day; /* day number of rule */
133 int r_week; /* week number of rule */
134 int r_mon; /* month number of rule */
135 int_fast32_t r_time; /* transition time of rule */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800136};
137
Calin Juravled8928922014-02-28 12:18:53 +0000138#define JULIAN_DAY 0 /* Jn - Julian day */
139#define DAY_OF_YEAR 1 /* n - day of year */
140#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800141
142/*
143** Prototypes for static functions.
144*/
145
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700146/* NOTE: all internal functions assume that _tzLock() was already called */
147
Elliott Hughesd23af232012-10-17 16:30:47 -0700148static int __bionic_open_tzdata(const char*, int*);
Elliott Hughesce4783c2013-07-12 17:31:11 -0700149static int_fast32_t detzcode(const char * codep);
Calin Juravled8928922014-02-28 12:18:53 +0000150static int_fast64_t detzcode64(const char * codep);
Elliott Hughesce4783c2013-07-12 17:31:11 -0700151static int differ_by_repeat(time_t t1, time_t t0);
152static const char * getzname(const char * strp) ATTRIBUTE_PURE;
153static const char * getqzname(const char * strp, const int delim)
154 ATTRIBUTE_PURE;
155static const char * getnum(const char * strp, int * nump, int min,
156 int max);
157static const char * getsecs(const char * strp, int_fast32_t * secsp);
158static const char * getoffset(const char * strp, int_fast32_t * offsetp);
159static const char * getrule(const char * strp, struct rule * rulep);
160static void gmtload(struct state * sp);
161static struct tm * gmtsub(const time_t * timep, const int_fast32_t offset,
162 struct tm * tmp, const struct state * sp); // android-changed: added sp.
163static struct tm * localsub(const time_t * timep, int_fast32_t offset,
164 struct tm * tmp, const struct state * sp); // android-changed: added sp.
165static int increment_overflow(int * number, int delta);
166static int leaps_thru_end_of(int y) ATTRIBUTE_PURE;
167static int increment_overflow32(int_fast32_t * number, int delta);
Calin Juravled8928922014-02-28 12:18:53 +0000168static int increment_overflow_time(time_t *t, int_fast32_t delta);
Elliott Hughesce4783c2013-07-12 17:31:11 -0700169static int normalize_overflow32(int_fast32_t * tensptr,
170 int * unitsptr, int base);
171static int normalize_overflow(int * tensptr, int * unitsptr,
172 int base);
173static void settzname(void);
174static time_t time1(struct tm * tmp,
175 struct tm * (*funcp)(const time_t *,
176 int_fast32_t, struct tm *, const struct state *), // android-changed: added state*.
177 int_fast32_t offset, const struct state * sp); // android-changed: added sp.
178static time_t time2(struct tm * const tmp,
179 struct tm * (*const funcp)(const time_t *,
180 int_fast32_t, struct tm*, const struct state *), // android-changed: added state*.
181 int_fast32_t offset, int * okayp, const struct state * sp); // android-changed: added sp.
182static time_t time2sub(struct tm *tmp,
183 struct tm * (*funcp) (const time_t *,
184 int_fast32_t, struct tm*, const struct state *), // android-changed: added state*.
185 int_fast32_t offset, int * okayp, int do_norm_secs, const struct state * sp); // android-change: added sp.
186static struct tm * timesub(const time_t * timep, int_fast32_t offset,
187 const struct state * sp, struct tm * tmp);
188static int tmcomp(const struct tm * atmp,
189 const struct tm * btmp);
Calin Juravled8928922014-02-28 12:18:53 +0000190static int_fast32_t transtime(int year, const struct rule * rulep,
191 int_fast32_t offset)
Elliott Hughesce4783c2013-07-12 17:31:11 -0700192 ATTRIBUTE_PURE;
Calin Juravled8928922014-02-28 12:18:53 +0000193static int typesequiv(const struct state * sp, int a, int b);
Elliott Hughesce4783c2013-07-12 17:31:11 -0700194static int tzload(const char * name, struct state * sp,
195 int doextend);
196static int tzparse(const char * name, struct state * sp,
197 int lastditch);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800198
199#ifdef ALL_STATE
Calin Juravled8928922014-02-28 12:18:53 +0000200static struct state * lclptr;
201static struct state * gmtptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800202#endif /* defined ALL_STATE */
203
204#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700205static struct state lclmem;
206static struct state gmtmem;
207#define lclptr (&lclmem)
208#define gmtptr (&gmtmem)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800209#endif /* State Farm */
210
211#ifndef TZ_STRLEN_MAX
212#define TZ_STRLEN_MAX 255
213#endif /* !defined TZ_STRLEN_MAX */
214
Calin Juravled8928922014-02-28 12:18:53 +0000215static char lcl_TZname[TZ_STRLEN_MAX + 1];
216static int lcl_is_set;
217static int gmt_is_set;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800218
Calin Juravled8928922014-02-28 12:18:53 +0000219char * tzname[2] = {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700220 wildabbr,
221 wildabbr
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800222};
223
224/*
225** Section 4.12.3 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700226** Except for the strftime function, these functions [asctime,
227** ctime, gmtime, localtime] return values in one of two static
228** objects: a broken-down time structure and an array of char.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800229** Thanks to Paul Eggert for noting this.
230*/
231
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700232static struct tm tmGlobal;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800233
234#ifdef USG_COMPAT
Calin Juravled8928922014-02-28 12:18:53 +0000235long timezone = 0;
236int daylight = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800237#endif /* defined USG_COMPAT */
238
239#ifdef ALTZONE
Calin Juravled8928922014-02-28 12:18:53 +0000240long altzone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800241#endif /* defined ALTZONE */
242
Elliott Hughesce4783c2013-07-12 17:31:11 -0700243static int_fast32_t
244detzcode(const char *const codep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800245{
Calin Juravled8928922014-02-28 12:18:53 +0000246 register int_fast32_t result;
247 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800248
Calin Juravled8928922014-02-28 12:18:53 +0000249 result = (codep[0] & 0x80) ? -1 : 0;
250 for (i = 0; i < 4; ++i)
251 result = (result << 8) | (codep[i] & 0xff);
252 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800253}
254
Calin Juravle627d37c2014-02-28 11:46:03 +0000255static int_fast64_t
Elliott Hughesce4783c2013-07-12 17:31:11 -0700256detzcode64(const char *const codep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800257{
Calin Juravled8928922014-02-28 12:18:53 +0000258 register int_fast64_t result;
259 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800260
Calin Juravled8928922014-02-28 12:18:53 +0000261 result = (codep[0] & 0x80) ? -1 : 0;
262 for (i = 0; i < 8; ++i)
263 result = (result << 8) | (codep[i] & 0xff);
264 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800265}
266
267static void
Elliott Hughesce4783c2013-07-12 17:31:11 -0700268settzname(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800269{
Calin Juravled8928922014-02-28 12:18:53 +0000270 register struct state * const sp = lclptr;
271 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800272
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700273 tzname[0] = wildabbr;
274 tzname[1] = wildabbr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800275#ifdef USG_COMPAT
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700276 daylight = 0;
277 timezone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800278#endif /* defined USG_COMPAT */
279#ifdef ALTZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700280 altzone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800281#endif /* defined ALTZONE */
282#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700283 if (sp == NULL) {
284 tzname[0] = tzname[1] = gmt;
285 return;
286 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800287#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700288 /*
289 ** And to get the latest zone names into tzname. . .
290 */
Elliott Hughesce4783c2013-07-12 17:31:11 -0700291 for (i = 0; i < sp->typecnt; ++i) {
292 register const struct ttinfo * const ttisp = &sp->ttis[i];
293
294 tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind];
295 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700296 for (i = 0; i < sp->timecnt; ++i) {
297 register const struct ttinfo * const ttisp =
298 &sp->ttis[
299 sp->types[i]];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800300
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700301 tzname[ttisp->tt_isdst] =
302 &sp->chars[ttisp->tt_abbrind];
Elliott Hughesce4783c2013-07-12 17:31:11 -0700303#ifdef USG_COMPAT
304 if (ttisp->tt_isdst)
305 daylight = 1;
306 if (!ttisp->tt_isdst)
307 timezone = -(ttisp->tt_gmtoff);
308#endif /* defined USG_COMPAT */
309#ifdef ALTZONE
310 if (ttisp->tt_isdst)
311 altzone = -(ttisp->tt_gmtoff);
312#endif /* defined ALTZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700313 }
314 /*
315 ** Finally, scrub the abbreviations.
316 ** First, replace bogus characters.
317 */
318 for (i = 0; i < sp->charcnt; ++i)
319 if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
320 sp->chars[i] = TZ_ABBR_ERR_CHAR;
321 /*
322 ** Second, truncate long abbreviations.
323 */
324 for (i = 0; i < sp->typecnt; ++i) {
325 register const struct ttinfo * const ttisp = &sp->ttis[i];
326 register char * cp = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800327
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700328 if (strlen(cp) > TZ_ABBR_MAX_LEN &&
329 strcmp(cp, GRANDPARENTED) != 0)
330 *(cp + TZ_ABBR_MAX_LEN) = '\0';
331 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800332}
333
334static int
Elliott Hughesce4783c2013-07-12 17:31:11 -0700335differ_by_repeat(const time_t t1, const time_t t0)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800336{
Calin Juravled8928922014-02-28 12:18:53 +0000337 if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
338 return 0;
Elliott Hughes51aeff72013-10-08 18:30:44 -0700339#if __LP64__ // 32-bit Android only has a signed 32-bit time_t; 64-bit Android is fixed.
Calin Juravled8928922014-02-28 12:18:53 +0000340 return t1 - t0 == SECSPERREPEAT;
Elliott Hughes51aeff72013-10-08 18:30:44 -0700341#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800342}
343
344static int
Elliott Hughesce4783c2013-07-12 17:31:11 -0700345tzload(register const char* name, register struct state* const sp,
346 register const int doextend)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800347{
Calin Juravled8928922014-02-28 12:18:53 +0000348 register const char * p;
349 register int i;
350 register int fid;
351 register int stored;
352 register int nread;
Elliott Hughesce4783c2013-07-12 17:31:11 -0700353 typedef union {
Calin Juravled8928922014-02-28 12:18:53 +0000354 struct tzhead tzhead;
355 char buf[2 * sizeof(struct tzhead) +
356 2 * sizeof *sp +
357 4 * TZ_MAX_TIMES];
Elliott Hughesce4783c2013-07-12 17:31:11 -0700358 } u_t;
359#ifdef ALL_STATE
Calin Juravled8928922014-02-28 12:18:53 +0000360 register u_t * up;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800361
Elliott Hughesce4783c2013-07-12 17:31:11 -0700362 up = (u_t *) calloc(1, sizeof *up);
363 if (up == NULL)
364 return -1;
365#else /* !defined ALL_STATE */
Calin Juravled8928922014-02-28 12:18:53 +0000366 u_t u;
367 register u_t * const up = &u;
Elliott Hughesce4783c2013-07-12 17:31:11 -0700368#endif /* !defined ALL_STATE */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800369
Elliott Hughesce4783c2013-07-12 17:31:11 -0700370 sp->goback = sp->goahead = FALSE;
371 if (name == NULL && (name = TZDEFAULT) == NULL)
372 goto oops;
373 int toread;
374 fid = __bionic_open_tzdata(name, &toread);
Elliott Hughes3073f902014-02-27 17:04:38 -0800375 if (fid < 0)
376 goto oops;
Elliott Hughesce4783c2013-07-12 17:31:11 -0700377 nread = read(fid, up->buf, toread);
378 if (close(fid) < 0 || nread <= 0)
379 goto oops;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700380 for (stored = 4; stored <= 8; stored *= 2) {
Calin Juravled8928922014-02-28 12:18:53 +0000381 int ttisstdcnt;
382 int ttisgmtcnt;
383 int timecnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800384
Elliott Hughesce4783c2013-07-12 17:31:11 -0700385 ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt);
386 ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt);
387 sp->leapcnt = (int) detzcode(up->tzhead.tzh_leapcnt);
388 sp->timecnt = (int) detzcode(up->tzhead.tzh_timecnt);
389 sp->typecnt = (int) detzcode(up->tzhead.tzh_typecnt);
390 sp->charcnt = (int) detzcode(up->tzhead.tzh_charcnt);
391 p = up->tzhead.tzh_charcnt + sizeof up->tzhead.tzh_charcnt;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700392 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
393 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
394 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
395 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
396 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
397 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
Elliott Hughesce4783c2013-07-12 17:31:11 -0700398 goto oops;
399 if (nread - (p - up->buf) <
Calin Juravled8928922014-02-28 12:18:53 +0000400 sp->timecnt * stored + /* ats */
401 sp->timecnt + /* types */
402 sp->typecnt * 6 + /* ttinfos */
403 sp->charcnt + /* chars */
404 sp->leapcnt * (stored + 4) + /* lsinfos */
405 ttisstdcnt + /* ttisstds */
406 ttisgmtcnt) /* ttisgmts */
Elliott Hughesce4783c2013-07-12 17:31:11 -0700407 goto oops;
Calin Juravled8928922014-02-28 12:18:53 +0000408 timecnt = 0;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700409 for (i = 0; i < sp->timecnt; ++i) {
Calin Juravled8928922014-02-28 12:18:53 +0000410 int_fast64_t at
411 = stored == 4 ? detzcode(p) : detzcode64(p);
412 sp->types[i] = ((TYPE_SIGNED(time_t)
413 ? time_t_min <= at
414 : 0 <= at)
415 && at <= time_t_max);
416 if (sp->types[i]) {
417 if (i && !timecnt && at != time_t_min) {
418 /*
419 ** Keep the earlier record, but tweak
420 ** it so that it starts with the
421 ** minimum time_t value.
422 */
423 sp->types[i - 1] = 1;
424 sp->ats[timecnt++] = time_t_min;
425 }
426 sp->ats[timecnt++] = at;
427 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700428 p += stored;
429 }
Calin Juravled8928922014-02-28 12:18:53 +0000430 timecnt = 0;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700431 for (i = 0; i < sp->timecnt; ++i) {
Calin Juravled8928922014-02-28 12:18:53 +0000432 unsigned char typ = *p++;
433 if (sp->typecnt <= typ)
Elliott Hughesce4783c2013-07-12 17:31:11 -0700434 goto oops;
Calin Juravled8928922014-02-28 12:18:53 +0000435 if (sp->types[i])
436 sp->types[timecnt++] = typ;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700437 }
Calin Juravled8928922014-02-28 12:18:53 +0000438 sp->timecnt = timecnt;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700439 for (i = 0; i < sp->typecnt; ++i) {
440 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800441
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700442 ttisp = &sp->ttis[i];
443 ttisp->tt_gmtoff = detzcode(p);
444 p += 4;
445 ttisp->tt_isdst = (unsigned char) *p++;
446 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
Elliott Hughesce4783c2013-07-12 17:31:11 -0700447 goto oops;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700448 ttisp->tt_abbrind = (unsigned char) *p++;
449 if (ttisp->tt_abbrind < 0 ||
450 ttisp->tt_abbrind > sp->charcnt)
Elliott Hughesce4783c2013-07-12 17:31:11 -0700451 goto oops;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700452 }
453 for (i = 0; i < sp->charcnt; ++i)
454 sp->chars[i] = *p++;
455 sp->chars[i] = '\0'; /* ensure '\0' at end */
456 for (i = 0; i < sp->leapcnt; ++i) {
457 register struct lsinfo * lsisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800458
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700459 lsisp = &sp->lsis[i];
460 lsisp->ls_trans = (stored == 4) ?
461 detzcode(p) : detzcode64(p);
462 p += stored;
463 lsisp->ls_corr = detzcode(p);
464 p += 4;
465 }
466 for (i = 0; i < sp->typecnt; ++i) {
467 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800468
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700469 ttisp = &sp->ttis[i];
470 if (ttisstdcnt == 0)
471 ttisp->tt_ttisstd = FALSE;
472 else {
473 ttisp->tt_ttisstd = *p++;
474 if (ttisp->tt_ttisstd != TRUE &&
475 ttisp->tt_ttisstd != FALSE)
Elliott Hughesce4783c2013-07-12 17:31:11 -0700476 goto oops;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700477 }
478 }
479 for (i = 0; i < sp->typecnt; ++i) {
480 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800481
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700482 ttisp = &sp->ttis[i];
483 if (ttisgmtcnt == 0)
484 ttisp->tt_ttisgmt = FALSE;
485 else {
486 ttisp->tt_ttisgmt = *p++;
487 if (ttisp->tt_ttisgmt != TRUE &&
488 ttisp->tt_ttisgmt != FALSE)
Elliott Hughesce4783c2013-07-12 17:31:11 -0700489 goto oops;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700490 }
491 }
492 /*
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700493 ** If this is an old file, we're done.
494 */
Elliott Hughesce4783c2013-07-12 17:31:11 -0700495 if (up->tzhead.tzh_version[0] == '\0')
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700496 break;
Elliott Hughesce4783c2013-07-12 17:31:11 -0700497 nread -= p - up->buf;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700498 for (i = 0; i < nread; ++i)
Elliott Hughesce4783c2013-07-12 17:31:11 -0700499 up->buf[i] = p[i];
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700500 /*
Calin Juravled8928922014-02-28 12:18:53 +0000501 ** If this is a signed narrow time_t system, we're done.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700502 */
Calin Juravled8928922014-02-28 12:18:53 +0000503 if (TYPE_SIGNED(time_t) && stored >= (int) sizeof(time_t))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700504 break;
505 }
506 if (doextend && nread > 2 &&
Elliott Hughesce4783c2013-07-12 17:31:11 -0700507 up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700508 sp->typecnt + 2 <= TZ_MAX_TYPES) {
Calin Juravled8928922014-02-28 12:18:53 +0000509 struct state ts;
510 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800511
Elliott Hughesce4783c2013-07-12 17:31:11 -0700512 up->buf[nread - 1] = '\0';
513 result = tzparse(&up->buf[1], &ts, FALSE);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700514 if (result == 0 && ts.typecnt == 2 &&
515 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
516 for (i = 0; i < 2; ++i)
517 ts.ttis[i].tt_abbrind +=
518 sp->charcnt;
519 for (i = 0; i < ts.charcnt; ++i)
520 sp->chars[sp->charcnt++] =
521 ts.chars[i];
522 i = 0;
523 while (i < ts.timecnt &&
524 ts.ats[i] <=
525 sp->ats[sp->timecnt - 1])
526 ++i;
527 while (i < ts.timecnt &&
528 sp->timecnt < TZ_MAX_TIMES) {
529 sp->ats[sp->timecnt] =
530 ts.ats[i];
531 sp->types[sp->timecnt] =
532 sp->typecnt +
533 ts.types[i];
534 ++sp->timecnt;
535 ++i;
536 }
537 sp->ttis[sp->typecnt++] = ts.ttis[0];
538 sp->ttis[sp->typecnt++] = ts.ttis[1];
539 }
540 }
Elliott Hughesce4783c2013-07-12 17:31:11 -0700541 if (sp->timecnt > 1) {
542 for (i = 1; i < sp->timecnt; ++i)
543 if (typesequiv(sp, sp->types[i], sp->types[0]) &&
544 differ_by_repeat(sp->ats[i], sp->ats[0])) {
545 sp->goback = TRUE;
546 break;
547 }
548 for (i = sp->timecnt - 2; i >= 0; --i)
549 if (typesequiv(sp, sp->types[sp->timecnt - 1],
550 sp->types[i]) &&
551 differ_by_repeat(sp->ats[sp->timecnt - 1],
552 sp->ats[i])) {
553 sp->goahead = TRUE;
554 break;
555 }
556 }
557 /*
558 ** If type 0 is is unused in transitions,
559 ** it's the type to use for early times.
560 */
561 for (i = 0; i < sp->typecnt; ++i)
562 if (sp->types[i] == 0)
563 break;
564 i = (i >= sp->typecnt) ? 0 : -1;
565 /*
566 ** Absent the above,
567 ** if there are transition times
568 ** and the first transition is to a daylight time
569 ** find the standard type less than and closest to
570 ** the type of the first transition.
571 */
572 if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
573 i = sp->types[0];
574 while (--i >= 0)
575 if (!sp->ttis[i].tt_isdst)
576 break;
577 }
578 /*
579 ** If no result yet, find the first standard type.
580 ** If there is none, punt to type zero.
581 */
582 if (i < 0) {
583 i = 0;
584 while (sp->ttis[i].tt_isdst)
585 if (++i >= sp->typecnt) {
586 i = 0;
587 break;
588 }
589 }
590 sp->defaulttype = i;
591#ifdef ALL_STATE
592 free(up);
593#endif /* defined ALL_STATE */
594 return 0;
595oops:
596#ifdef ALL_STATE
597 free(up);
598#endif /* defined ALL_STATE */
599 return -1;
600}
601
602static int
603typesequiv(const struct state *const sp, const int a, const int b)
604{
Calin Juravled8928922014-02-28 12:18:53 +0000605 register int result;
Elliott Hughesce4783c2013-07-12 17:31:11 -0700606
Calin Juravled8928922014-02-28 12:18:53 +0000607 if (sp == NULL ||
608 a < 0 || a >= sp->typecnt ||
609 b < 0 || b >= sp->typecnt)
610 result = FALSE;
611 else {
612 register const struct ttinfo * ap = &sp->ttis[a];
613 register const struct ttinfo * bp = &sp->ttis[b];
614 result = ap->tt_gmtoff == bp->tt_gmtoff &&
615 ap->tt_isdst == bp->tt_isdst &&
616 ap->tt_ttisstd == bp->tt_ttisstd &&
617 ap->tt_ttisgmt == bp->tt_ttisgmt &&
618 strcmp(&sp->chars[ap->tt_abbrind],
619 &sp->chars[bp->tt_abbrind]) == 0;
620 }
621 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800622}
623
Calin Juravled8928922014-02-28 12:18:53 +0000624static const int mon_lengths[2][MONSPERYEAR] = {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700625 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
626 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800627};
628
Calin Juravled8928922014-02-28 12:18:53 +0000629static const int year_lengths[2] = {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700630 DAYSPERNYEAR, DAYSPERLYEAR
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800631};
632
633/*
634** Given a pointer into a time zone string, scan until a character that is not
635** a valid character in a zone name is found. Return a pointer to that
636** character.
637*/
638
639static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700640getzname(register const char * strp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800641{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700642 register char c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800643
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700644 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
645 c != '+')
646 ++strp;
647 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800648}
649
650/*
651** Given a pointer into an extended time zone string, scan until the ending
652** delimiter of the zone name is located. Return a pointer to the delimiter.
653**
654** As with getzname above, the legal character set is actually quite
655** restricted, with other characters producing undefined results.
656** We don't do any checking here; checking is done later in common-case code.
657*/
658
659static const char *
660getqzname(register const char *strp, const int delim)
661{
Calin Juravled8928922014-02-28 12:18:53 +0000662 register int c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800663
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700664 while ((c = *strp) != '\0' && c != delim)
665 ++strp;
666 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800667}
668
669/*
670** Given a pointer into a time zone string, extract a number from that string.
671** Check that the number is within a specified range; if it is not, return
672** NULL.
673** Otherwise, return a pointer to the first character not part of the number.
674*/
675
676static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700677getnum(register const char * strp, int * const nump, const int min, const int max)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800678{
Calin Juravled8928922014-02-28 12:18:53 +0000679 register char c;
680 register int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800681
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700682 if (strp == NULL || !is_digit(c = *strp))
683 return NULL;
684 num = 0;
685 do {
686 num = num * 10 + (c - '0');
687 if (num > max)
688 return NULL; /* illegal value */
689 c = *++strp;
690 } while (is_digit(c));
691 if (num < min)
692 return NULL; /* illegal value */
693 *nump = num;
694 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800695}
696
697/*
698** Given a pointer into a time zone string, extract a number of seconds,
699** in hh[:mm[:ss]] form, from the string.
700** If any error occurs, return NULL.
701** Otherwise, return a pointer to the first character not part of the number
702** of seconds.
703*/
704
705static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700706getsecs(register const char *strp, int_fast32_t *const secsp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800707{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700708 int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800709
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700710 /*
711 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
712 ** "M10.4.6/26", which does not conform to Posix,
713 ** but which specifies the equivalent of
714 ** ``02:00 on the first Sunday on or after 23 Oct''.
715 */
716 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
717 if (strp == NULL)
718 return NULL;
Elliott Hughesce4783c2013-07-12 17:31:11 -0700719 *secsp = num * (int_fast32_t) SECSPERHOUR;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700720 if (*strp == ':') {
721 ++strp;
722 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
723 if (strp == NULL)
724 return NULL;
725 *secsp += num * SECSPERMIN;
726 if (*strp == ':') {
727 ++strp;
728 /* `SECSPERMIN' allows for leap seconds. */
729 strp = getnum(strp, &num, 0, SECSPERMIN);
730 if (strp == NULL)
731 return NULL;
732 *secsp += num;
733 }
734 }
735 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800736}
737
738/*
739** Given a pointer into a time zone string, extract an offset, in
740** [+-]hh[:mm[:ss]] form, from the string.
741** If any error occurs, return NULL.
742** Otherwise, return a pointer to the first character not part of the time.
743*/
744
745static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700746getoffset(register const char *strp, int_fast32_t *const offsetp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800747{
Calin Juravled8928922014-02-28 12:18:53 +0000748 register int neg = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800749
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700750 if (*strp == '-') {
751 neg = 1;
752 ++strp;
753 } else if (*strp == '+')
754 ++strp;
755 strp = getsecs(strp, offsetp);
756 if (strp == NULL)
757 return NULL; /* illegal time */
758 if (neg)
759 *offsetp = -*offsetp;
760 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800761}
762
763/*
764** Given a pointer into a time zone string, extract a rule in the form
765** date[/time]. See POSIX section 8 for the format of "date" and "time".
766** If a valid rule is not found, return NULL.
767** Otherwise, return a pointer to the first character not part of the rule.
768*/
769
770static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700771getrule(const char * strp, register struct rule * const rulep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800772{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700773 if (*strp == 'J') {
774 /*
775 ** Julian day.
776 */
777 rulep->r_type = JULIAN_DAY;
778 ++strp;
779 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
780 } else if (*strp == 'M') {
781 /*
782 ** Month, week, day.
783 */
784 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
785 ++strp;
786 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
787 if (strp == NULL)
788 return NULL;
789 if (*strp++ != '.')
790 return NULL;
791 strp = getnum(strp, &rulep->r_week, 1, 5);
792 if (strp == NULL)
793 return NULL;
794 if (*strp++ != '.')
795 return NULL;
796 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
797 } else if (is_digit(*strp)) {
798 /*
799 ** Day of year.
800 */
801 rulep->r_type = DAY_OF_YEAR;
802 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
803 } else return NULL; /* invalid format */
804 if (strp == NULL)
805 return NULL;
806 if (*strp == '/') {
807 /*
808 ** Time specified.
809 */
810 ++strp;
Elliott Hughese0d0b152013-09-27 00:04:30 -0700811 strp = getoffset(strp, &rulep->r_time);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700812 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
813 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800814}
815
816/*
Calin Juravle627d37c2014-02-28 11:46:03 +0000817** Given a year, a rule, and the offset from UT at the time that rule takes
818** effect, calculate the year-relative time that rule takes effect.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800819*/
820
Calin Juravle627d37c2014-02-28 11:46:03 +0000821static int_fast32_t
822transtime(const int year, register const struct rule *const rulep,
Calin Juravled8928922014-02-28 12:18:53 +0000823 const int_fast32_t offset)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800824{
Calin Juravled8928922014-02-28 12:18:53 +0000825 register int leapyear;
826 register int_fast32_t value;
827 register int i;
828 int d, m1, yy0, yy1, yy2, dow;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800829
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700830 INITIALIZE(value);
831 leapyear = isleap(year);
832 switch (rulep->r_type) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800833
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700834 case JULIAN_DAY:
835 /*
836 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
837 ** years.
838 ** In non-leap years, or if the day number is 59 or less, just
839 ** add SECSPERDAY times the day number-1 to the time of
840 ** January 1, midnight, to get the day.
841 */
Calin Juravled8928922014-02-28 12:18:53 +0000842 value = (rulep->r_day - 1) * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700843 if (leapyear && rulep->r_day >= 60)
844 value += SECSPERDAY;
845 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800846
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700847 case DAY_OF_YEAR:
848 /*
849 ** n - day of year.
850 ** Just add SECSPERDAY times the day number to the time of
851 ** January 1, midnight, to get the day.
852 */
Calin Juravled8928922014-02-28 12:18:53 +0000853 value = rulep->r_day * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700854 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800855
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700856 case MONTH_NTH_DAY_OF_WEEK:
857 /*
858 ** Mm.n.d - nth "dth day" of month m.
859 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800860
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700861 /*
862 ** Use Zeller's Congruence to get day-of-week of first day of
863 ** month.
864 */
865 m1 = (rulep->r_mon + 9) % 12 + 1;
866 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
867 yy1 = yy0 / 100;
868 yy2 = yy0 % 100;
869 dow = ((26 * m1 - 2) / 10 +
870 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
871 if (dow < 0)
872 dow += DAYSPERWEEK;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800873
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700874 /*
875 ** "dow" is the day-of-week of the first day of the month. Get
876 ** the day-of-month (zero-origin) of the first "dow" day of the
877 ** month.
878 */
879 d = rulep->r_day - dow;
880 if (d < 0)
881 d += DAYSPERWEEK;
882 for (i = 1; i < rulep->r_week; ++i) {
883 if (d + DAYSPERWEEK >=
884 mon_lengths[leapyear][rulep->r_mon - 1])
885 break;
886 d += DAYSPERWEEK;
887 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800888
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700889 /*
890 ** "d" is the day-of-month (zero-origin) of the day we want.
891 */
Calin Juravled8928922014-02-28 12:18:53 +0000892 value = d * SECSPERDAY;
893 for (i = 0; i < rulep->r_mon - 1; ++i)
894 value += mon_lengths[leapyear][i] * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700895 break;
896 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800897
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700898 /*
Calin Juravled8928922014-02-28 12:18:53 +0000899 ** "value" is the year-relative time of 00:00:00 UT on the day in
900 ** question. To get the year-relative time of the specified local
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700901 ** time on that day, add the transition time and the current offset
Elliott Hughese0d0b152013-09-27 00:04:30 -0700902 ** from UT.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700903 */
904 return value + rulep->r_time + offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800905}
906
907/*
908** Given a POSIX section 8-style TZ string, fill in the rule tables as
909** appropriate.
910*/
911
912static int
Elliott Hughesce4783c2013-07-12 17:31:11 -0700913tzparse(const char * name, register struct state * const sp,
914 const int lastditch)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800915{
Calin Juravled8928922014-02-28 12:18:53 +0000916 const char * stdname;
917 const char * dstname;
918 size_t stdlen;
919 size_t dstlen;
920 int_fast32_t stdoffset;
921 int_fast32_t dstoffset;
922 register char * cp;
923 register int load_result;
924 static struct ttinfo zttinfo;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800925
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700926 INITIALIZE(dstname);
927 stdname = name;
928 if (lastditch) {
929 stdlen = strlen(name); /* length of standard zone name */
930 name += stdlen;
931 if (stdlen >= sizeof sp->chars)
932 stdlen = (sizeof sp->chars) - 1;
933 stdoffset = 0;
934 } else {
935 if (*name == '<') {
936 name++;
937 stdname = name;
938 name = getqzname(name, '>');
939 if (*name != '>')
940 return (-1);
941 stdlen = name - stdname;
942 name++;
943 } else {
944 name = getzname(name);
945 stdlen = name - stdname;
946 }
947 if (*name == '\0')
948 return -1;
949 name = getoffset(name, &stdoffset);
950 if (name == NULL)
951 return -1;
952 }
953 load_result = tzload(TZDEFRULES, sp, FALSE);
954 if (load_result != 0)
955 sp->leapcnt = 0; /* so, we're off a little */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700956 if (*name != '\0') {
957 if (*name == '<') {
958 dstname = ++name;
959 name = getqzname(name, '>');
960 if (*name != '>')
961 return -1;
962 dstlen = name - dstname;
963 name++;
964 } else {
965 dstname = name;
966 name = getzname(name);
967 dstlen = name - dstname; /* length of DST zone name */
968 }
969 if (*name != '\0' && *name != ',' && *name != ';') {
970 name = getoffset(name, &dstoffset);
971 if (name == NULL)
972 return -1;
973 } else dstoffset = stdoffset - SECSPERHOUR;
974 if (*name == '\0' && load_result != 0)
975 name = TZDEFRULESTRING;
976 if (*name == ',' || *name == ';') {
Calin Juravled8928922014-02-28 12:18:53 +0000977 struct rule start;
978 struct rule end;
979 register int year;
980 register int yearlim;
981 register int timecnt;
982 time_t janfirst;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800983
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700984 ++name;
985 if ((name = getrule(name, &start)) == NULL)
986 return -1;
987 if (*name++ != ',')
988 return -1;
989 if ((name = getrule(name, &end)) == NULL)
990 return -1;
991 if (*name != '\0')
992 return -1;
993 sp->typecnt = 2; /* standard time and DST */
994 /*
995 ** Two transitions per year, from EPOCH_YEAR forward.
996 */
Elliott Hughesce4783c2013-07-12 17:31:11 -0700997 sp->ttis[0] = sp->ttis[1] = zttinfo;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700998 sp->ttis[0].tt_gmtoff = -dstoffset;
999 sp->ttis[0].tt_isdst = 1;
1000 sp->ttis[0].tt_abbrind = stdlen + 1;
1001 sp->ttis[1].tt_gmtoff = -stdoffset;
1002 sp->ttis[1].tt_isdst = 0;
1003 sp->ttis[1].tt_abbrind = 0;
Calin Juravled8928922014-02-28 12:18:53 +00001004 timecnt = 0;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001005 janfirst = 0;
Elliott Hughese0d0b152013-09-27 00:04:30 -07001006 yearlim = EPOCH_YEAR + YEARSPERREPEAT;
1007 for (year = EPOCH_YEAR; year < yearlim; year++) {
Calin Juravled8928922014-02-28 12:18:53 +00001008 int_fast32_t
1009 starttime = transtime(year, &start, stdoffset),
1010 endtime = transtime(year, &end, dstoffset);
1011 int_fast32_t
Elliott Hughese0d0b152013-09-27 00:04:30 -07001012 yearsecs = (year_lengths[isleap(year)]
1013 * SECSPERDAY);
Calin Juravled8928922014-02-28 12:18:53 +00001014 int reversed = endtime < starttime;
1015 if (reversed) {
1016 int_fast32_t swap = starttime;
1017 starttime = endtime;
1018 endtime = swap;
1019 }
1020 if (reversed
Elliott Hughese0d0b152013-09-27 00:04:30 -07001021 || (starttime < endtime
1022 && (endtime - starttime
1023 < (yearsecs
1024 + (stdoffset - dstoffset))))) {
Calin Juravled8928922014-02-28 12:18:53 +00001025 if (TZ_MAX_TIMES - 2 < timecnt)
Elliott Hughese0d0b152013-09-27 00:04:30 -07001026 break;
1027 yearlim = year + YEARSPERREPEAT + 1;
Calin Juravled8928922014-02-28 12:18:53 +00001028 sp->ats[timecnt] = janfirst;
1029 if (increment_overflow_time
1030 (&sp->ats[timecnt], starttime))
1031 break;
1032 sp->types[timecnt++] = reversed;
1033 sp->ats[timecnt] = janfirst;
1034 if (increment_overflow_time
1035 (&sp->ats[timecnt], endtime))
1036 break;
1037 sp->types[timecnt++] = !reversed;
Elliott Hughese0d0b152013-09-27 00:04:30 -07001038 }
Calin Juravled8928922014-02-28 12:18:53 +00001039 if (increment_overflow_time(&janfirst, yearsecs))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001040 break;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001041 }
Calin Juravled8928922014-02-28 12:18:53 +00001042 sp->timecnt = timecnt;
1043 if (!timecnt)
1044 sp->typecnt = 1; /* Perpetual DST. */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001045 } else {
Elliott Hughesce4783c2013-07-12 17:31:11 -07001046 register int_fast32_t theirstdoffset;
1047 register int_fast32_t theirdstoffset;
1048 register int_fast32_t theiroffset;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001049 register int isdst;
1050 register int i;
1051 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001052
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001053 if (*name != '\0')
1054 return -1;
1055 /*
1056 ** Initial values of theirstdoffset and theirdstoffset.
1057 */
1058 theirstdoffset = 0;
1059 for (i = 0; i < sp->timecnt; ++i) {
1060 j = sp->types[i];
1061 if (!sp->ttis[j].tt_isdst) {
1062 theirstdoffset =
1063 -sp->ttis[j].tt_gmtoff;
1064 break;
1065 }
1066 }
1067 theirdstoffset = 0;
1068 for (i = 0; i < sp->timecnt; ++i) {
1069 j = sp->types[i];
1070 if (sp->ttis[j].tt_isdst) {
1071 theirdstoffset =
1072 -sp->ttis[j].tt_gmtoff;
1073 break;
1074 }
1075 }
1076 /*
1077 ** Initially we're assumed to be in standard time.
1078 */
1079 isdst = FALSE;
1080 theiroffset = theirstdoffset;
1081 /*
1082 ** Now juggle transition times and types
1083 ** tracking offsets as you do.
1084 */
1085 for (i = 0; i < sp->timecnt; ++i) {
1086 j = sp->types[i];
1087 sp->types[i] = sp->ttis[j].tt_isdst;
1088 if (sp->ttis[j].tt_ttisgmt) {
1089 /* No adjustment to transition time */
1090 } else {
1091 /*
1092 ** If summer time is in effect, and the
1093 ** transition time was not specified as
1094 ** standard time, add the summer time
1095 ** offset to the transition time;
1096 ** otherwise, add the standard time
1097 ** offset to the transition time.
1098 */
1099 /*
1100 ** Transitions from DST to DDST
1101 ** will effectively disappear since
1102 ** POSIX provides for only one DST
1103 ** offset.
1104 */
1105 if (isdst && !sp->ttis[j].tt_ttisstd) {
1106 sp->ats[i] += dstoffset -
1107 theirdstoffset;
1108 } else {
1109 sp->ats[i] += stdoffset -
1110 theirstdoffset;
1111 }
1112 }
1113 theiroffset = -sp->ttis[j].tt_gmtoff;
1114 if (sp->ttis[j].tt_isdst)
1115 theirdstoffset = theiroffset;
1116 else theirstdoffset = theiroffset;
1117 }
1118 /*
1119 ** Finally, fill in ttis.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001120 */
Elliott Hughesce4783c2013-07-12 17:31:11 -07001121 sp->ttis[0] = sp->ttis[1] = zttinfo;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001122 sp->ttis[0].tt_gmtoff = -stdoffset;
1123 sp->ttis[0].tt_isdst = FALSE;
1124 sp->ttis[0].tt_abbrind = 0;
1125 sp->ttis[1].tt_gmtoff = -dstoffset;
1126 sp->ttis[1].tt_isdst = TRUE;
1127 sp->ttis[1].tt_abbrind = stdlen + 1;
1128 sp->typecnt = 2;
1129 }
1130 } else {
1131 dstlen = 0;
1132 sp->typecnt = 1; /* only standard time */
1133 sp->timecnt = 0;
Elliott Hughesce4783c2013-07-12 17:31:11 -07001134 sp->ttis[0] = zttinfo;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001135 sp->ttis[0].tt_gmtoff = -stdoffset;
1136 sp->ttis[0].tt_isdst = 0;
1137 sp->ttis[0].tt_abbrind = 0;
1138 }
1139 sp->charcnt = stdlen + 1;
1140 if (dstlen != 0)
1141 sp->charcnt += dstlen + 1;
1142 if ((size_t) sp->charcnt > sizeof sp->chars)
1143 return -1;
1144 cp = sp->chars;
1145 (void) strncpy(cp, stdname, stdlen);
1146 cp += stdlen;
1147 *cp++ = '\0';
1148 if (dstlen != 0) {
1149 (void) strncpy(cp, dstname, dstlen);
1150 *(cp + dstlen) = '\0';
1151 }
1152 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001153}
1154
1155static void
Elliott Hughesce4783c2013-07-12 17:31:11 -07001156gmtload(struct state * const sp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001157{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001158 if (tzload(gmt, sp, TRUE) != 0)
1159 (void) tzparse(gmt, sp, TRUE);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001160}
1161
Elliott Hughesce4783c2013-07-12 17:31:11 -07001162#ifndef STD_INSPIRED
1163/*
1164** A non-static declaration of tzsetwall in a system header file
1165** may cause a warning about this upcoming static declaration...
1166*/
1167static
1168#endif /* !defined STD_INSPIRED */
1169void
1170tzsetwall(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001171{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001172 if (lcl_is_set < 0)
1173 return;
1174 lcl_is_set = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001175
1176#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001177 if (lclptr == NULL) {
Elliott Hughesce4783c2013-07-12 17:31:11 -07001178 lclptr = calloc(1, sizeof *lclptr);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001179 if (lclptr == NULL) {
1180 settzname(); /* all we can do */
1181 return;
1182 }
1183 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001184#endif /* defined ALL_STATE */
Elliott Hughesce4783c2013-07-12 17:31:11 -07001185 if (tzload(NULL, lclptr, TRUE) != 0)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001186 gmtload(lclptr);
1187 settzname();
1188}
1189
Elliott Hughesce4783c2013-07-12 17:31:11 -07001190#include <sys/system_properties.h> // For __system_property_get.
1191
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001192static void
Elliott Hughesce4783c2013-07-12 17:31:11 -07001193tzset_locked(void)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001194{
Calin Juravled8928922014-02-28 12:18:53 +00001195 register const char * name = NULL;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001196
1197 name = getenv("TZ");
1198
1199 // try the "persist.sys.timezone" system property first
Elliott Hughesce4783c2013-07-12 17:31:11 -07001200 static char buf[PROP_VALUE_MAX];
1201 if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0) {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001202 name = buf;
Elliott Hughesce4783c2013-07-12 17:31:11 -07001203 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001204
1205 if (name == NULL) {
1206 tzsetwall();
1207 return;
1208 }
1209
1210 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
1211 return;
1212 lcl_is_set = strlen(name) < sizeof lcl_TZname;
1213 if (lcl_is_set)
1214 (void) strcpy(lcl_TZname, name);
1215
1216#ifdef ALL_STATE
1217 if (lclptr == NULL) {
Elliott Hughesce4783c2013-07-12 17:31:11 -07001218 lclptr = calloc(1, sizeof *lclptr);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001219 if (lclptr == NULL) {
1220 settzname(); /* all we can do */
1221 return;
1222 }
1223 }
1224#endif /* defined ALL_STATE */
1225 if (*name == '\0') {
1226 /*
1227 ** User wants it fast rather than right.
1228 */
1229 lclptr->leapcnt = 0; /* so, we're off a little */
1230 lclptr->timecnt = 0;
1231 lclptr->typecnt = 0;
1232 lclptr->ttis[0].tt_isdst = 0;
1233 lclptr->ttis[0].tt_gmtoff = 0;
1234 lclptr->ttis[0].tt_abbrind = 0;
1235 (void) strcpy(lclptr->chars, gmt);
1236 } else if (tzload(name, lclptr, TRUE) != 0)
1237 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
1238 (void) gmtload(lclptr);
1239 settzname();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001240}
1241
1242void
Elliott Hughesce4783c2013-07-12 17:31:11 -07001243tzset(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001244{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001245 _tzLock();
1246 tzset_locked();
1247 _tzUnlock();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001248}
1249
1250/*
1251** The easy way to behave "as if no library function calls" localtime
1252** is to not call it--so we drop its guts into "localsub", which can be
1253** freely called. (And no, the PANS doesn't require the above behavior--
1254** but it *is* desirable.)
1255**
1256** The unused offset argument is for the benefit of mktime variants.
1257*/
1258
1259/*ARGSUSED*/
1260static struct tm *
Elliott Hughesce4783c2013-07-12 17:31:11 -07001261localsub(const time_t * const timep, const int_fast32_t offset,
1262 struct tm * const tmp, const struct state * sp) // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001263{
Calin Juravled8928922014-02-28 12:18:53 +00001264 register const struct ttinfo * ttisp;
1265 register int i;
1266 register struct tm * result;
1267 const time_t t = *timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001268
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001269 // BEGIN android-changed: support user-supplied sp.
1270 if (sp == NULL) {
1271 sp = lclptr;
1272 }
1273 // END android-changed
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001274#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001275 if (sp == NULL)
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001276 return gmtsub(timep, offset, tmp, sp); // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001277#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001278 if ((sp->goback && t < sp->ats[0]) ||
1279 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1280 time_t newt = t;
Calin Juravled8928922014-02-28 12:18:53 +00001281 register time_t seconds;
1282 register time_t years;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001283
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001284 if (t < sp->ats[0])
1285 seconds = sp->ats[0] - t;
1286 else seconds = t - sp->ats[sp->timecnt - 1];
1287 --seconds;
Elliott Hughese0d0b152013-09-27 00:04:30 -07001288 years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
1289 seconds = years * AVGSECSPERYEAR;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001290 if (t < sp->ats[0])
1291 newt += seconds;
1292 else newt -= seconds;
1293 if (newt < sp->ats[0] ||
1294 newt > sp->ats[sp->timecnt - 1])
1295 return NULL; /* "cannot happen" */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001296 result = localsub(&newt, offset, tmp, sp); // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001297 if (result == tmp) {
1298 register time_t newy;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001299
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001300 newy = tmp->tm_year;
1301 if (t < sp->ats[0])
Elliott Hughese0d0b152013-09-27 00:04:30 -07001302 newy -= years;
1303 else newy += years;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001304 tmp->tm_year = newy;
1305 if (tmp->tm_year != newy)
1306 return NULL;
1307 }
1308 return result;
1309 }
1310 if (sp->timecnt == 0 || t < sp->ats[0]) {
Elliott Hughesce4783c2013-07-12 17:31:11 -07001311 i = sp->defaulttype;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001312 } else {
Calin Juravled8928922014-02-28 12:18:53 +00001313 register int lo = 1;
1314 register int hi = sp->timecnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001315
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001316 while (lo < hi) {
1317 register int mid = (lo + hi) >> 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001318
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001319 if (t < sp->ats[mid])
1320 hi = mid;
1321 else lo = mid + 1;
1322 }
1323 i = (int) sp->types[lo - 1];
1324 }
1325 ttisp = &sp->ttis[i];
1326 /*
1327 ** To get (wrong) behavior that's compatible with System V Release 2.0
1328 ** you'd replace the statement below with
1329 ** t += ttisp->tt_gmtoff;
1330 ** timesub(&t, 0L, sp, tmp);
1331 */
1332 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1333 tmp->tm_isdst = ttisp->tt_isdst;
1334 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001335#ifdef TM_ZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001336 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001337#endif /* defined TM_ZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001338 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001339}
1340
1341struct tm *
Elliott Hughesce4783c2013-07-12 17:31:11 -07001342localtime(const time_t * const timep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001343{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001344 return localtime_r(timep, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001345}
1346
1347/*
1348** Re-entrant version of localtime.
1349*/
1350
1351struct tm *
Elliott Hughesce4783c2013-07-12 17:31:11 -07001352localtime_r(const time_t * const timep, struct tm * tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001353{
Calin Juravled8928922014-02-28 12:18:53 +00001354 struct tm* result;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001355
1356 _tzLock();
1357 tzset_locked();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001358 result = localsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001359 _tzUnlock();
1360
1361 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001362}
1363
1364/*
1365** gmtsub is to gmtime as localsub is to localtime.
1366*/
1367
1368static struct tm *
Elliott Hughesce4783c2013-07-12 17:31:11 -07001369gmtsub(const time_t * const timep, const int_fast32_t offset,
1370 struct tm *const tmp, const struct state * sp) // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001371{
Calin Juravled8928922014-02-28 12:18:53 +00001372 register struct tm * result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001373
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001374 (void) sp; // android-added: unused.
1375
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001376 if (!gmt_is_set) {
1377 gmt_is_set = TRUE;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001378#ifdef ALL_STATE
Elliott Hughesce4783c2013-07-12 17:31:11 -07001379 gmtptr = calloc(1, sizeof *gmtptr);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001380 if (gmtptr != NULL)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001381#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001382 gmtload(gmtptr);
1383 }
1384 result = timesub(timep, offset, gmtptr, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001385#ifdef TM_ZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001386 /*
1387 ** Could get fancy here and deliver something such as
Elliott Hughese0d0b152013-09-27 00:04:30 -07001388 ** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001389 ** but this is no time for a treasure hunt.
1390 */
1391 if (offset != 0)
1392 tmp->TM_ZONE = wildabbr;
1393 else {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001394#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001395 if (gmtptr == NULL)
1396 tmp->TM_ZONE = gmt;
1397 else tmp->TM_ZONE = gmtptr->chars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001398#endif /* defined ALL_STATE */
1399#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001400 tmp->TM_ZONE = gmtptr->chars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001401#endif /* State Farm */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001402 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001403#endif /* defined TM_ZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001404 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001405}
1406
1407struct tm *
Elliott Hughesce4783c2013-07-12 17:31:11 -07001408gmtime(const time_t * const timep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001409{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001410 return gmtime_r(timep, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001411}
1412
1413/*
1414* Re-entrant version of gmtime.
1415*/
1416
1417struct tm *
Elliott Hughesce4783c2013-07-12 17:31:11 -07001418gmtime_r(const time_t * const timep, struct tm * tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001419{
Calin Juravled8928922014-02-28 12:18:53 +00001420 struct tm* result;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001421
1422 _tzLock();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001423 result = gmtsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001424 _tzUnlock();
1425
1426 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001427}
1428
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001429/*
1430** Return the number of leap years through the end of the given year
1431** where, to make the math easy, the answer for year zero is defined as zero.
1432*/
1433
1434static int
Elliott Hughesce4783c2013-07-12 17:31:11 -07001435leaps_thru_end_of(register const int y)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001436{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001437 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1438 -(leaps_thru_end_of(-(y + 1)) + 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001439}
1440
1441static struct tm *
Elliott Hughesce4783c2013-07-12 17:31:11 -07001442timesub(const time_t *const timep, const int_fast32_t offset,
1443 register const struct state *const sp,
1444 register struct tm *const tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001445{
Calin Juravled8928922014-02-28 12:18:53 +00001446 register const struct lsinfo * lp;
1447 register time_t tdays;
1448 register int idays; /* unsigned would be so 2003 */
1449 register int_fast64_t rem;
1450 int y;
1451 register const int * ip;
1452 register int_fast64_t corr;
1453 register int hit;
1454 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001455
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001456 corr = 0;
1457 hit = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001458#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001459 i = (sp == NULL) ? 0 : sp->leapcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001460#endif /* defined ALL_STATE */
1461#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001462 i = sp->leapcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001463#endif /* State Farm */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001464 while (--i >= 0) {
1465 lp = &sp->lsis[i];
1466 if (*timep >= lp->ls_trans) {
1467 if (*timep == lp->ls_trans) {
1468 hit = ((i == 0 && lp->ls_corr > 0) ||
1469 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1470 if (hit)
1471 while (i > 0 &&
1472 sp->lsis[i].ls_trans ==
1473 sp->lsis[i - 1].ls_trans + 1 &&
1474 sp->lsis[i].ls_corr ==
1475 sp->lsis[i - 1].ls_corr + 1) {
1476 ++hit;
1477 --i;
1478 }
1479 }
1480 corr = lp->ls_corr;
1481 break;
1482 }
1483 }
1484 y = EPOCH_YEAR;
1485 tdays = *timep / SECSPERDAY;
1486 rem = *timep - tdays * SECSPERDAY;
1487 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1488 int newy;
1489 register time_t tdelta;
1490 register int idelta;
1491 register int leapdays;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001492
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001493 tdelta = tdays / DAYSPERLYEAR;
Elliott Hughese0d0b152013-09-27 00:04:30 -07001494 if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
1495 && tdelta <= INT_MAX))
1496 return NULL;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001497 idelta = tdelta;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001498 if (idelta == 0)
1499 idelta = (tdays < 0) ? -1 : 1;
1500 newy = y;
1501 if (increment_overflow(&newy, idelta))
1502 return NULL;
1503 leapdays = leaps_thru_end_of(newy - 1) -
1504 leaps_thru_end_of(y - 1);
1505 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1506 tdays -= leapdays;
1507 y = newy;
1508 }
1509 {
Elliott Hughesce4783c2013-07-12 17:31:11 -07001510 register int_fast32_t seconds;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001511
Elliott Hughese0d0b152013-09-27 00:04:30 -07001512 seconds = tdays * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001513 tdays = seconds / SECSPERDAY;
1514 rem += seconds - tdays * SECSPERDAY;
1515 }
1516 /*
1517 ** Given the range, we can now fearlessly cast...
1518 */
1519 idays = tdays;
1520 rem += offset - corr;
1521 while (rem < 0) {
1522 rem += SECSPERDAY;
1523 --idays;
1524 }
1525 while (rem >= SECSPERDAY) {
1526 rem -= SECSPERDAY;
1527 ++idays;
1528 }
1529 while (idays < 0) {
1530 if (increment_overflow(&y, -1))
1531 return NULL;
1532 idays += year_lengths[isleap(y)];
1533 }
1534 while (idays >= year_lengths[isleap(y)]) {
1535 idays -= year_lengths[isleap(y)];
1536 if (increment_overflow(&y, 1))
1537 return NULL;
1538 }
1539 tmp->tm_year = y;
1540 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1541 return NULL;
1542 tmp->tm_yday = idays;
1543 /*
1544 ** The "extra" mods below avoid overflow problems.
1545 */
1546 tmp->tm_wday = EPOCH_WDAY +
1547 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
1548 (DAYSPERNYEAR % DAYSPERWEEK) +
1549 leaps_thru_end_of(y - 1) -
1550 leaps_thru_end_of(EPOCH_YEAR - 1) +
1551 idays;
1552 tmp->tm_wday %= DAYSPERWEEK;
1553 if (tmp->tm_wday < 0)
1554 tmp->tm_wday += DAYSPERWEEK;
1555 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1556 rem %= SECSPERHOUR;
1557 tmp->tm_min = (int) (rem / SECSPERMIN);
1558 /*
1559 ** A positive leap second requires a special
1560 ** representation. This uses "... ??:59:60" et seq.
1561 */
1562 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1563 ip = mon_lengths[isleap(y)];
1564 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1565 idays -= ip[tmp->tm_mon];
1566 tmp->tm_mday = (int) (idays + 1);
1567 tmp->tm_isdst = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001568#ifdef TM_GMTOFF
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001569 tmp->TM_GMTOFF = offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001570#endif /* defined TM_GMTOFF */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001571 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001572}
1573
1574char *
Elliott Hughesce4783c2013-07-12 17:31:11 -07001575ctime(const time_t * const timep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001576{
1577/*
1578** Section 4.12.3.2 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001579** The ctime function converts the calendar time pointed to by timer
1580** to local time in the form of a string. It is equivalent to
1581** asctime(localtime(timer))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001582*/
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001583 return asctime(localtime(timep));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001584}
1585
1586char *
Elliott Hughesce4783c2013-07-12 17:31:11 -07001587ctime_r(const time_t * const timep, char * buf)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001588{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001589 struct tm mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001590
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001591 return asctime_r(localtime_r(timep, &mytm), buf);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001592}
1593
1594/*
1595** Adapted from code provided by Robert Elz, who writes:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001596** The "best" way to do mktime I think is based on an idea of Bob
1597** Kridle's (so its said...) from a long time ago.
1598** It does a binary search of the time_t space. Since time_t's are
1599** just 32 bits, its a max of 32 iterations (even at 64 bits it
1600** would still be very reasonable).
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001601*/
1602
1603#ifndef WRONG
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001604#define WRONG (-1)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001605#endif /* !defined WRONG */
1606
1607/*
Elliott Hughesce4783c2013-07-12 17:31:11 -07001608** Normalize logic courtesy Paul Eggert.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001609*/
1610
1611static int
Elliott Hughesce4783c2013-07-12 17:31:11 -07001612increment_overflow(int *const ip, int j)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001613{
Calin Juravled8928922014-02-28 12:18:53 +00001614 register int const i = *ip;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001615
Calin Juravled8928922014-02-28 12:18:53 +00001616 /*
1617 ** If i >= 0 there can only be overflow if i + j > INT_MAX
1618 ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
1619 ** If i < 0 there can only be overflow if i + j < INT_MIN
1620 ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
1621 */
1622 if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
1623 return TRUE;
1624 *ip += j;
1625 return FALSE;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001626}
1627
1628static int
Elliott Hughesce4783c2013-07-12 17:31:11 -07001629increment_overflow32(int_fast32_t *const lp, int const m)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001630{
Calin Juravled8928922014-02-28 12:18:53 +00001631 register int_fast32_t const l = *lp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001632
Calin Juravled8928922014-02-28 12:18:53 +00001633 if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
1634 return TRUE;
1635 *lp += m;
1636 return FALSE;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001637}
1638
1639static int
Calin Juravle627d37c2014-02-28 11:46:03 +00001640increment_overflow_time(time_t *tp, int_fast32_t j)
1641{
Calin Juravled8928922014-02-28 12:18:53 +00001642 /*
1643 ** This is like
1644 ** 'if (! (time_t_min <= *tp + j && *tp + j <= time_t_max)) ...',
1645 ** except that it does the right thing even if *tp + j would overflow.
1646 */
1647 if (! (j < 0
1648 ? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp)
1649 : *tp <= time_t_max - j))
1650 return TRUE;
1651 *tp += j;
1652 return FALSE;
Calin Juravle627d37c2014-02-28 11:46:03 +00001653}
1654
1655static int
Elliott Hughesce4783c2013-07-12 17:31:11 -07001656normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001657{
Calin Juravled8928922014-02-28 12:18:53 +00001658 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001659
Calin Juravled8928922014-02-28 12:18:53 +00001660 tensdelta = (*unitsptr >= 0) ?
1661 (*unitsptr / base) :
1662 (-1 - (-1 - *unitsptr) / base);
1663 *unitsptr -= tensdelta * base;
1664 return increment_overflow(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001665}
1666
1667static int
Elliott Hughesce4783c2013-07-12 17:31:11 -07001668normalize_overflow32(int_fast32_t *const tensptr, int *const unitsptr,
Calin Juravled8928922014-02-28 12:18:53 +00001669 const int base)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001670{
Calin Juravled8928922014-02-28 12:18:53 +00001671 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001672
Calin Juravled8928922014-02-28 12:18:53 +00001673 tensdelta = (*unitsptr >= 0) ?
1674 (*unitsptr / base) :
1675 (-1 - (-1 - *unitsptr) / base);
1676 *unitsptr -= tensdelta * base;
1677 return increment_overflow32(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001678}
1679
1680static int
Elliott Hughesce4783c2013-07-12 17:31:11 -07001681tmcomp(register const struct tm * const atmp,
1682 register const struct tm * const btmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001683{
Calin Juravled8928922014-02-28 12:18:53 +00001684 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001685
Elliott Hughese0d0b152013-09-27 00:04:30 -07001686 if (atmp->tm_year != btmp->tm_year)
1687 return atmp->tm_year < btmp->tm_year ? -1 : 1;
1688 if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001689 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1690 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1691 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1692 result = atmp->tm_sec - btmp->tm_sec;
1693 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001694}
1695
1696static time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07001697time2sub(struct tm * const tmp,
1698 struct tm *(*const funcp)(const time_t*, int_fast32_t, struct tm*, const struct state*),
1699 const int_fast32_t offset,
1700 int * const okayp,
1701 const int do_norm_secs, const struct state * sp) // android-changed: added sp
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001702{
Calin Juravled8928922014-02-28 12:18:53 +00001703 register int dir;
1704 register int i, j;
1705 register int saved_seconds;
1706 register int_fast32_t li;
1707 register time_t lo;
1708 register time_t hi;
1709 int_fast32_t y;
1710 time_t newt;
1711 time_t t;
1712 struct tm yourtm, mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001713
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001714 *okayp = FALSE;
1715 yourtm = *tmp;
1716 if (do_norm_secs) {
1717 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1718 SECSPERMIN))
1719 return WRONG;
1720 }
1721 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1722 return WRONG;
1723 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1724 return WRONG;
1725 y = yourtm.tm_year;
Elliott Hughesce4783c2013-07-12 17:31:11 -07001726 if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001727 return WRONG;
1728 /*
1729 ** Turn y into an actual year number for now.
1730 ** It is converted back to an offset from TM_YEAR_BASE later.
1731 */
Elliott Hughesce4783c2013-07-12 17:31:11 -07001732 if (increment_overflow32(&y, TM_YEAR_BASE))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001733 return WRONG;
1734 while (yourtm.tm_mday <= 0) {
Elliott Hughesce4783c2013-07-12 17:31:11 -07001735 if (increment_overflow32(&y, -1))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001736 return WRONG;
1737 li = y + (1 < yourtm.tm_mon);
1738 yourtm.tm_mday += year_lengths[isleap(li)];
1739 }
1740 while (yourtm.tm_mday > DAYSPERLYEAR) {
1741 li = y + (1 < yourtm.tm_mon);
1742 yourtm.tm_mday -= year_lengths[isleap(li)];
Elliott Hughesce4783c2013-07-12 17:31:11 -07001743 if (increment_overflow32(&y, 1))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001744 return WRONG;
1745 }
1746 for ( ; ; ) {
1747 i = mon_lengths[isleap(y)][yourtm.tm_mon];
1748 if (yourtm.tm_mday <= i)
1749 break;
1750 yourtm.tm_mday -= i;
1751 if (++yourtm.tm_mon >= MONSPERYEAR) {
1752 yourtm.tm_mon = 0;
Elliott Hughesce4783c2013-07-12 17:31:11 -07001753 if (increment_overflow32(&y, 1))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001754 return WRONG;
1755 }
1756 }
Elliott Hughesce4783c2013-07-12 17:31:11 -07001757 if (increment_overflow32(&y, -TM_YEAR_BASE))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001758 return WRONG;
1759 yourtm.tm_year = y;
1760 if (yourtm.tm_year != y)
1761 return WRONG;
1762 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
1763 saved_seconds = 0;
1764 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
1765 /*
1766 ** We can't set tm_sec to 0, because that might push the
1767 ** time below the minimum representable time.
1768 ** Set tm_sec to 59 instead.
1769 ** This assumes that the minimum representable time is
1770 ** not in the same minute that a leap second was deleted from,
1771 ** which is a safer assumption than using 58 would be.
1772 */
1773 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1774 return WRONG;
1775 saved_seconds = yourtm.tm_sec;
1776 yourtm.tm_sec = SECSPERMIN - 1;
1777 } else {
1778 saved_seconds = yourtm.tm_sec;
1779 yourtm.tm_sec = 0;
1780 }
1781 /*
1782 ** Do a binary search (this works whatever time_t's type is).
1783 */
1784 if (!TYPE_SIGNED(time_t)) {
1785 lo = 0;
1786 hi = lo - 1;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001787 } else {
1788 lo = 1;
1789 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
1790 lo *= 2;
1791 hi = -(lo + 1);
1792 }
1793 for ( ; ; ) {
1794 t = lo / 2 + hi / 2;
1795 if (t < lo)
1796 t = lo;
1797 else if (t > hi)
1798 t = hi;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001799 if ((*funcp)(&t, offset, &mytm, sp) == NULL) { // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001800 /*
1801 ** Assume that t is too extreme to be represented in
1802 ** a struct tm; arrange things so that it is less
1803 ** extreme on the next pass.
1804 */
1805 dir = (t > 0) ? 1 : -1;
1806 } else dir = tmcomp(&mytm, &yourtm);
1807 if (dir != 0) {
1808 if (t == lo) {
Elliott Hughes713fe642013-08-22 14:13:50 -07001809 if (t == time_t_max)
Elliott Hughesce4783c2013-07-12 17:31:11 -07001810 return WRONG;
Elliott Hughes713fe642013-08-22 14:13:50 -07001811 ++t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001812 ++lo;
1813 } else if (t == hi) {
Elliott Hughes713fe642013-08-22 14:13:50 -07001814 if (t == time_t_min)
Elliott Hughesce4783c2013-07-12 17:31:11 -07001815 return WRONG;
Elliott Hughes713fe642013-08-22 14:13:50 -07001816 --t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001817 --hi;
1818 }
1819 if (lo > hi)
1820 return WRONG;
1821 if (dir > 0)
1822 hi = t;
1823 else lo = t;
1824 continue;
1825 }
1826 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1827 break;
1828 /*
1829 ** Right time, wrong type.
1830 ** Hunt for right time, right type.
1831 ** It's okay to guess wrong since the guess
1832 ** gets checked.
1833 */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001834 // BEGIN android-changed: support user-supplied sp
1835 if (sp == NULL) {
1836 sp = (const struct state *)
Elliott Hughesce4783c2013-07-12 17:31:11 -07001837 ((funcp == localsub) ? lclptr : gmtptr);
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001838 }
1839 // END android-changed
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001840#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001841 if (sp == NULL)
1842 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001843#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001844 for (i = sp->typecnt - 1; i >= 0; --i) {
1845 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1846 continue;
1847 for (j = sp->typecnt - 1; j >= 0; --j) {
1848 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1849 continue;
1850 newt = t + sp->ttis[j].tt_gmtoff -
1851 sp->ttis[i].tt_gmtoff;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001852 if ((*funcp)(&newt, offset, &mytm, sp) == NULL) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001853 continue;
1854 if (tmcomp(&mytm, &yourtm) != 0)
1855 continue;
1856 if (mytm.tm_isdst != yourtm.tm_isdst)
1857 continue;
1858 /*
1859 ** We have a match.
1860 */
1861 t = newt;
1862 goto label;
1863 }
1864 }
1865 return WRONG;
1866 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001867label:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001868 newt = t + saved_seconds;
1869 if ((newt < t) != (saved_seconds < 0))
1870 return WRONG;
1871 t = newt;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001872 if ((*funcp)(&t, offset, tmp, sp)) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001873 *okayp = TRUE;
1874 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001875}
1876
1877static time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07001878time2(struct tm * const tmp,
1879 struct tm * (*const funcp)(const time_t *, int_fast32_t, struct tm *, const struct state *), // android-changed: added sp.
1880 const int_fast32_t offset,
1881 int *const okayp, const struct state* sp) // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001882{
Calin Juravled8928922014-02-28 12:18:53 +00001883 time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001884
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001885 /*
1886 ** First try without normalization of seconds
1887 ** (in case tm_sec contains a value associated with a leap second).
1888 ** If that fails, try with normalization of seconds.
1889 */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001890 t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
1891 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001892}
1893
1894static time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07001895time1(struct tm * const tmp,
1896 struct tm * (* const funcp) (const time_t *, int_fast32_t, struct tm *, const struct state *), // android-changed: added sp.
1897 const int_fast32_t offset, const struct state * sp) // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001898{
Calin Juravled8928922014-02-28 12:18:53 +00001899 register time_t t;
1900 register int samei, otheri;
1901 register int sameind, otherind;
1902 register int i;
1903 register int nseen;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001904 int seen[TZ_MAX_TYPES];
1905 int types[TZ_MAX_TYPES];
1906 int okay;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001907
Elliott Hughesce4783c2013-07-12 17:31:11 -07001908 if (tmp == NULL) {
1909 errno = EINVAL;
1910 return WRONG;
1911 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001912 if (tmp->tm_isdst > 1)
1913 tmp->tm_isdst = 1;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001914 t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001915#ifdef PCTS
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001916 /*
1917 ** PCTS code courtesy Grant Sullivan.
1918 */
1919 if (okay)
1920 return t;
1921 if (tmp->tm_isdst < 0)
1922 tmp->tm_isdst = 0; /* reset to std and try again */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001923#endif /* defined PCTS */
1924#ifndef PCTS
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001925 if (okay || tmp->tm_isdst < 0)
1926 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001927#endif /* !defined PCTS */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001928 /*
1929 ** We're supposed to assume that somebody took a time of one type
1930 ** and did some math on it that yielded a "struct tm" that's bad.
1931 ** We try to divine the type they started from and adjust to the
1932 ** type they need.
1933 */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001934 // BEGIN android-changed: support user-supplied sp.
1935 if (sp == NULL) {
Elliott Hughesce4783c2013-07-12 17:31:11 -07001936 sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001937 }
1938 // BEGIN android-changed
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001939#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001940 if (sp == NULL)
1941 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001942#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001943 for (i = 0; i < sp->typecnt; ++i)
1944 seen[i] = FALSE;
1945 nseen = 0;
1946 for (i = sp->timecnt - 1; i >= 0; --i)
1947 if (!seen[sp->types[i]]) {
1948 seen[sp->types[i]] = TRUE;
1949 types[nseen++] = sp->types[i];
1950 }
1951 for (sameind = 0; sameind < nseen; ++sameind) {
1952 samei = types[sameind];
1953 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1954 continue;
1955 for (otherind = 0; otherind < nseen; ++otherind) {
1956 otheri = types[otherind];
1957 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1958 continue;
1959 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1960 sp->ttis[samei].tt_gmtoff;
1961 tmp->tm_isdst = !tmp->tm_isdst;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001962 t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001963 if (okay)
1964 return t;
1965 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1966 sp->ttis[samei].tt_gmtoff;
1967 tmp->tm_isdst = !tmp->tm_isdst;
1968 }
1969 }
1970 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001971}
1972
1973time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07001974mktime(struct tm * const tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001975{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001976 _tzLock();
1977 tzset_locked();
Elliott Hughesce4783c2013-07-12 17:31:11 -07001978 time_t result = time1(tmp, localsub, 0L, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001979 _tzUnlock();
1980 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001981}
1982
1983#ifdef STD_INSPIRED
1984
1985time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07001986timelocal(struct tm * const tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001987{
Elliott Hughesce4783c2013-07-12 17:31:11 -07001988 if (tmp != NULL)
1989 tmp->tm_isdst = -1; /* in case it wasn't initialized */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001990 return mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001991}
1992
1993time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07001994timegm(struct tm * const tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001995{
Calin Juravled8928922014-02-28 12:18:53 +00001996 time_t result;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001997
Elliott Hughesce4783c2013-07-12 17:31:11 -07001998 if (tmp != NULL)
1999 tmp->tm_isdst = 0;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002000 _tzLock();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002001 result = time1(tmp, gmtsub, 0L, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002002 _tzUnlock();
2003
2004 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002005}
2006
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002007#endif /* defined STD_INSPIRED */
2008
2009#ifdef CMUCS
2010
2011/*
2012** The following is supplied for compatibility with
2013** previous versions of the CMUCS runtime library.
2014*/
2015
Elliott Hughese0d0b152013-09-27 00:04:30 -07002016long
Elliott Hughesce4783c2013-07-12 17:31:11 -07002017gtime(struct tm * const tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002018{
Calin Juravled8928922014-02-28 12:18:53 +00002019 const time_t t = mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002020
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002021 if (t == WRONG)
2022 return -1;
2023 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002024}
2025
2026#endif /* defined CMUCS */
2027
2028/*
2029** XXX--is the below the right way to conditionalize??
2030*/
2031
2032#ifdef STD_INSPIRED
2033
2034/*
2035** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2036** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2037** is not the case if we are accounting for leap seconds.
2038** So, we provide the following conversion routines for use
2039** when exchanging timestamps with POSIX conforming systems.
2040*/
2041
Elliott Hughesce4783c2013-07-12 17:31:11 -07002042static int_fast64_t
2043leapcorr(time_t * timep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002044{
Calin Juravled8928922014-02-28 12:18:53 +00002045 register struct state * sp;
2046 register struct lsinfo * lp;
2047 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002048
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002049 sp = lclptr;
2050 i = sp->leapcnt;
2051 while (--i >= 0) {
2052 lp = &sp->lsis[i];
2053 if (*timep >= lp->ls_trans)
2054 return lp->ls_corr;
2055 }
2056 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002057}
2058
2059time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07002060time2posix(time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002061{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002062 tzset();
2063 return t - leapcorr(&t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002064}
2065
2066time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07002067posix2time(time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002068{
Calin Juravled8928922014-02-28 12:18:53 +00002069 time_t x;
2070 time_t y;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002071
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002072 tzset();
2073 /*
2074 ** For a positive leap second hit, the result
2075 ** is not unique. For a negative leap second
2076 ** hit, the corresponding time doesn't exist,
2077 ** so we return an adjacent second.
2078 */
2079 x = t + leapcorr(&t);
2080 y = x - leapcorr(&x);
2081 if (y < t) {
2082 do {
2083 x++;
2084 y = x - leapcorr(&x);
2085 } while (y < t);
2086 if (t != y)
2087 return x - 1;
2088 } else if (y > t) {
2089 do {
2090 --x;
2091 y = x - leapcorr(&x);
2092 } while (y > t);
2093 if (t != y)
2094 return x + 1;
2095 }
2096 return x;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002097}
2098
2099#endif /* defined STD_INSPIRED */
Elliott Hughesd23af232012-10-17 16:30:47 -07002100
Elliott Hughesce4783c2013-07-12 17:31:11 -07002101// BEGIN android-added
2102
Elliott Hughes1c295722012-10-19 18:13:15 -07002103#include <assert.h>
Elliott Hughesd23af232012-10-17 16:30:47 -07002104#include <stdint.h>
Elliott Hughes8b954042012-10-18 13:42:59 -07002105#include <arpa/inet.h> // For ntohl(3).
Elliott Hughesd23af232012-10-17 16:30:47 -07002106
Elliott Hughesce4783c2013-07-12 17:31:11 -07002107static int to_int(unsigned char* s) {
2108 return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
2109}
2110
Elliott Hughescf178bf2013-09-18 19:25:28 -07002111static int __bionic_open_tzdata_path(const char* path_prefix_variable, const char* path_suffix,
2112 const char* olson_id, int* data_size) {
2113 const char* path_prefix = getenv(path_prefix_variable);
2114 if (path_prefix == NULL) {
2115 fprintf(stderr, "%s: %s not set!\n", __FUNCTION__, path_prefix_variable);
2116 return -1;
2117 }
Elliott Hughes329103d2014-04-25 16:55:04 -07002118 size_t path_length = strlen(path_prefix) + 1 + strlen(path_suffix) + 1;
2119 char* path = malloc(path_length);
2120 if (path == NULL) {
2121 fprintf(stderr, "%s: couldn't allocate %zu-byte path\n", __FUNCTION__, path_length);
2122 return -1;
2123 }
2124 snprintf(path, path_length, "%s/%s", path_prefix, path_suffix);
Elliott Hughes1c295722012-10-19 18:13:15 -07002125 int fd = TEMP_FAILURE_RETRY(open(path, OPEN_MODE));
Elliott Hughesd23af232012-10-17 16:30:47 -07002126 if (fd == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002127 XLOG(("%s: could not open \"%s\": %s\n", __FUNCTION__, path, strerror(errno)));
Elliott Hughes329103d2014-04-25 16:55:04 -07002128 free(path);
Elliott Hughes1c295722012-10-19 18:13:15 -07002129 return -2; // Distinguish failure to find any data from failure to find a specific id.
Elliott Hughesd23af232012-10-17 16:30:47 -07002130 }
2131
2132 // byte[12] tzdata_version -- "tzdata2012f\0"
Elliott Hughesd23af232012-10-17 16:30:47 -07002133 // int index_offset
2134 // int data_offset
2135 // int zonetab_offset
2136 struct bionic_tzdata_header {
2137 char tzdata_version[12];
Elliott Hughesd23af232012-10-17 16:30:47 -07002138 int32_t index_offset;
2139 int32_t data_offset;
2140 int32_t zonetab_offset;
2141 } header;
Elliott Hughese7aaad82013-04-25 14:02:59 -07002142 memset(&header, 0, sizeof(header));
2143 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header)));
2144 if (bytes_read != sizeof(header)) {
2145 fprintf(stderr, "%s: could not read header of \"%s\": %s\n",
2146 __FUNCTION__, path, (bytes_read == -1) ? strerror(errno) : "short read");
Elliott Hughes329103d2014-04-25 16:55:04 -07002147 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002148 close(fd);
2149 return -1;
2150 }
2151
2152 if (strncmp(header.tzdata_version, "tzdata", 6) != 0 || header.tzdata_version[11] != 0) {
Elliott Hughese7aaad82013-04-25 14:02:59 -07002153 fprintf(stderr, "%s: bad magic in \"%s\": \"%.6s\"\n",
2154 __FUNCTION__, path, header.tzdata_version);
Elliott Hughes329103d2014-04-25 16:55:04 -07002155 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002156 close(fd);
2157 return -1;
2158 }
Elliott Hughesd23af232012-10-17 16:30:47 -07002159
2160#if 0
Elliott Hughes23935352012-10-22 14:47:58 -07002161 fprintf(stderr, "version: %s\n", header.tzdata_version);
Elliott Hughesd23af232012-10-17 16:30:47 -07002162 fprintf(stderr, "index_offset = %d\n", ntohl(header.index_offset));
2163 fprintf(stderr, "data_offset = %d\n", ntohl(header.data_offset));
2164 fprintf(stderr, "zonetab_offset = %d\n", ntohl(header.zonetab_offset));
2165#endif
2166
2167 if (TEMP_FAILURE_RETRY(lseek(fd, ntohl(header.index_offset), SEEK_SET)) == -1) {
Elliott Hughese7aaad82013-04-25 14:02:59 -07002168 fprintf(stderr, "%s: couldn't seek to index in \"%s\": %s\n",
2169 __FUNCTION__, path, strerror(errno));
Elliott Hughes329103d2014-04-25 16:55:04 -07002170 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002171 close(fd);
2172 return -1;
2173 }
2174
2175 off_t specific_zone_offset = -1;
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002176 ssize_t index_size = ntohl(header.data_offset) - ntohl(header.index_offset);
2177 char* index = malloc(index_size);
Elliott Hughes329103d2014-04-25 16:55:04 -07002178 if (index == NULL) {
2179 fprintf(stderr, "%s: couldn't allocate %zd-byte index for \"%s\"\n",
2180 __FUNCTION__, index_size, path);
2181 free(path);
2182 close(fd);
2183 return -1;
2184 }
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002185 if (TEMP_FAILURE_RETRY(read(fd, index, index_size)) != index_size) {
2186 fprintf(stderr, "%s: could not read index of \"%s\": %s\n",
2187 __FUNCTION__, path, (bytes_read == -1) ? strerror(errno) : "short read");
Elliott Hughes329103d2014-04-25 16:55:04 -07002188 free(path);
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002189 free(index);
2190 close(fd);
2191 return -1;
2192 }
Elliott Hughesd23af232012-10-17 16:30:47 -07002193
Elliott Hughes1c295722012-10-19 18:13:15 -07002194 static const size_t NAME_LENGTH = 40;
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002195 struct index_entry_t {
2196 char buf[NAME_LENGTH];
2197 int32_t start;
2198 int32_t length;
2199 int32_t raw_gmt_offset;
2200 };
Elliott Hughese0175ca2013-03-14 14:38:08 -07002201
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002202 size_t id_count = (ntohl(header.data_offset) - ntohl(header.index_offset)) / sizeof(struct index_entry_t);
2203 struct index_entry_t* entry = (struct index_entry_t*) index;
Elliott Hughese0175ca2013-03-14 14:38:08 -07002204 for (size_t i = 0; i < id_count; ++i) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002205 char this_id[NAME_LENGTH + 1];
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002206 memcpy(this_id, entry->buf, NAME_LENGTH);
Elliott Hughes1c295722012-10-19 18:13:15 -07002207 this_id[NAME_LENGTH] = '\0';
Elliott Hughesd23af232012-10-17 16:30:47 -07002208
2209 if (strcmp(this_id, olson_id) == 0) {
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002210 specific_zone_offset = ntohl(entry->start) + ntohl(header.data_offset);
2211 *data_size = ntohl(entry->length);
Elliott Hughesd23af232012-10-17 16:30:47 -07002212 break;
2213 }
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002214
2215 ++entry;
Elliott Hughesd23af232012-10-17 16:30:47 -07002216 }
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002217 free(index);
Elliott Hughesd23af232012-10-17 16:30:47 -07002218
2219 if (specific_zone_offset == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002220 XLOG(("%s: couldn't find zone \"%s\"\n", __FUNCTION__, olson_id));
Elliott Hughes329103d2014-04-25 16:55:04 -07002221 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002222 close(fd);
2223 return -1;
2224 }
2225
2226 if (TEMP_FAILURE_RETRY(lseek(fd, specific_zone_offset, SEEK_SET)) == -1) {
Elliott Hughese7aaad82013-04-25 14:02:59 -07002227 fprintf(stderr, "%s: could not seek to %ld in \"%s\": %s\n",
2228 __FUNCTION__, specific_zone_offset, path, strerror(errno));
Elliott Hughes329103d2014-04-25 16:55:04 -07002229 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002230 close(fd);
2231 return -1;
2232 }
2233
Elliott Hughese7aaad82013-04-25 14:02:59 -07002234 // TODO: check that there's TZ_MAGIC at this offset, so we can fall back to the other file if not.
2235
Elliott Hughes329103d2014-04-25 16:55:04 -07002236 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002237 return fd;
2238}
Elliott Hughes1c295722012-10-19 18:13:15 -07002239
2240static int __bionic_open_tzdata(const char* olson_id, int* data_size) {
Elliott Hughescf178bf2013-09-18 19:25:28 -07002241 int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/tzdata", olson_id, data_size);
Elliott Hughes1c295722012-10-19 18:13:15 -07002242 if (fd < 0) {
Elliott Hughescf178bf2013-09-18 19:25:28 -07002243 fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata", olson_id, data_size);
Elliott Hughes1c295722012-10-19 18:13:15 -07002244 if (fd == -2) {
Elliott Hughes49271d82012-10-25 14:38:51 -07002245 // The first thing that 'recovery' does is try to format the current time. It doesn't have
2246 // any tzdata available, so we must not abort here --- doing so breaks the recovery image!
2247 fprintf(stderr, "%s: couldn't find any tzdata when looking for %s!\n", __FUNCTION__, olson_id);
Elliott Hughes1c295722012-10-19 18:13:15 -07002248 }
2249 }
2250 return fd;
2251}
Elliott Hughesce4783c2013-07-12 17:31:11 -07002252
2253// Caches the most recent timezone (http://b/8270865).
2254static int __bionic_tzload_cached(const char* name, struct state* const sp, const int doextend) {
2255 _tzLock();
2256
2257 // Our single-item cache.
2258 static char* gCachedTimeZoneName;
2259 static struct state gCachedTimeZone;
2260
2261 // Do we already have this timezone cached?
2262 if (gCachedTimeZoneName != NULL && strcmp(name, gCachedTimeZoneName) == 0) {
2263 *sp = gCachedTimeZone;
2264 _tzUnlock();
2265 return 0;
2266 }
2267
2268 // Can we load it?
2269 int rc = tzload(name, sp, doextend);
2270 if (rc == 0) {
2271 // Update the cache.
2272 free(gCachedTimeZoneName);
2273 gCachedTimeZoneName = strdup(name);
2274 gCachedTimeZone = *sp;
2275 }
2276
2277 _tzUnlock();
2278 return rc;
2279}
2280
2281// Non-standard API: mktime(3) but with an explicit timezone parameter.
2282time_t mktime_tz(struct tm* const tmp, const char* tz) {
2283 struct state st;
2284 if (__bionic_tzload_cached(tz, &st, TRUE) != 0) {
2285 // TODO: not sure what's best here, but for now, we fall back to gmt.
2286 gmtload(&st);
2287 }
2288 return time1(tmp, localsub, 0L, &st);
2289}
2290
2291// Non-standard API: localtime(3) but with an explicit timezone parameter.
2292void localtime_tz(const time_t* const timep, struct tm* tmp, const char* tz) {
2293 struct state st;
2294 if (__bionic_tzload_cached(tz, &st, TRUE) != 0) {
2295 // TODO: not sure what's best here, but for now, we fall back to gmt.
2296 gmtload(&st);
2297 }
2298 localsub(timep, 0L, tmp, &st);
2299}
2300
2301// END android-added