blob: 447907e0f0f621bb078b643dd3be8acaf86756bd [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
6#ifndef lint
7#ifndef NOID
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07008static char elsieid[] = "@(#)localtime.c 8.3";
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08009#endif /* !defined NOID */
10#endif /* !defined lint */
11
12/*
13** Leap second handling from Bradley White.
14** POSIX-style TZ environment variable handling from Guy Harris.
15*/
16
17/*LINTLIBRARY*/
18
19#include "private.h"
20#include "tzfile.h"
21#include "fcntl.h"
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070022#include "float.h" /* for FLT_MAX and DBL_MAX */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080023
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070024#include "thread_private.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080025#include <sys/system_properties.h>
26
27#ifndef TZ_ABBR_MAX_LEN
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070028#define TZ_ABBR_MAX_LEN 16
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080029#endif /* !defined TZ_ABBR_MAX_LEN */
30
31#ifndef TZ_ABBR_CHAR_SET
32#define TZ_ABBR_CHAR_SET \
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070033 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080034#endif /* !defined TZ_ABBR_CHAR_SET */
35
36#ifndef TZ_ABBR_ERR_CHAR
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070037#define TZ_ABBR_ERR_CHAR '_'
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080038#endif /* !defined TZ_ABBR_ERR_CHAR */
39
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080040/*
41** SunOS 4.1.1 headers lack O_BINARY.
42*/
43
44#ifdef O_BINARY
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070045#define OPEN_MODE (O_RDONLY | O_BINARY)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080046#endif /* defined O_BINARY */
47#ifndef O_BINARY
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070048#define OPEN_MODE O_RDONLY
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080049#endif /* !defined O_BINARY */
50
51#if 0
52# define XLOG(xx) printf xx , fflush(stdout)
53#else
54# define XLOG(x) do{}while (0)
55#endif
56
David 'Digit' Turner6481b912010-12-06 12:23:16 +010057/* Add the following function implementations:
58 * timelocal()
59 * timegm()
60 * time2posix()
61 * posix2time()
62 */
63#define STD_INSPIRED 1
64
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070065/* THREAD-SAFETY SUPPORT GOES HERE */
66static pthread_mutex_t _tzMutex = PTHREAD_MUTEX_INITIALIZER;
67
68static __inline__ void _tzLock(void)
69{
70 if (__isthreaded)
71 pthread_mutex_lock(&_tzMutex);
72}
73
74static __inline__ void _tzUnlock(void)
75{
76 if (__isthreaded)
77 pthread_mutex_unlock(&_tzMutex);
78}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080079
David 'Digit' Turner2093d352009-09-09 17:41:59 -070080/* Complex computations to determine the min/max of time_t depending
81 * on TYPE_BIT / TYPE_SIGNED / TYPE_INTEGRAL.
82 * These macros cannot be used in pre-processor directives, so we
83 * let the C compiler do the work, which makes things a bit funky.
84 */
85static const time_t TIME_T_MAX =
86 TYPE_INTEGRAL(time_t) ?
87 ( TYPE_SIGNED(time_t) ?
88 ~((time_t)1 << (TYPE_BIT(time_t)-1))
89 :
90 ~(time_t)0
91 )
92 : /* if time_t is a floating point number */
93 ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MAX : (time_t)FLT_MAX );
94
95static const time_t TIME_T_MIN =
96 TYPE_INTEGRAL(time_t) ?
97 ( TYPE_SIGNED(time_t) ?
98 ((time_t)1 << (TYPE_BIT(time_t)-1))
99 :
100 0
101 )
102 :
103 ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MIN : (time_t)FLT_MIN );
104
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800105#ifndef WILDABBR
106/*
107** Someone might make incorrect use of a time zone abbreviation:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700108** 1. They might reference tzname[0] before calling tzset (explicitly
109** or implicitly).
110** 2. They might reference tzname[1] before calling tzset (explicitly
111** or implicitly).
112** 3. They might reference tzname[1] after setting to a time zone
113** in which Daylight Saving Time is never observed.
114** 4. They might reference tzname[0] after setting to a time zone
115** in which Standard Time is never observed.
116** 5. They might reference tm.TM_ZONE after calling offtime.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800117** What's best to do in the above cases is open to debate;
118** for now, we just set things up so that in any of the five cases
119** WILDABBR is used. Another possibility: initialize tzname[0] to the
120** string "tzname[0] used before set", and similarly for the other cases.
121** And another: initialize tzname[0] to "ERA", with an explanation in the
122** manual page of what this "time zone abbreviation" means (doing this so
123** that tzname[0] has the "normal" length of three characters).
124*/
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700125#define WILDABBR " "
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800126#endif /* !defined WILDABBR */
127
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700128static char wildabbr[] = WILDABBR;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800129
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700130static const char gmt[] = "GMT";
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800131
132/*
133** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
134** We default to US rules as of 1999-08-17.
135** POSIX 1003.1 section 8.1.1 says that the default DST rules are
136** implementation dependent; for historical reasons, US rules are a
137** common default.
138*/
139#ifndef TZDEFRULESTRING
140#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
141#endif /* !defined TZDEFDST */
142
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700143struct ttinfo { /* time type information */
144 long tt_gmtoff; /* UTC offset in seconds */
145 int tt_isdst; /* used to set tm_isdst */
146 int tt_abbrind; /* abbreviation list index */
147 int tt_ttisstd; /* TRUE if transition is std time */
148 int tt_ttisgmt; /* TRUE if transition is UTC */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800149};
150
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700151struct lsinfo { /* leap second information */
152 time_t ls_trans; /* transition time */
153 long ls_corr; /* correction to apply */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800154};
155
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700156#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800157
158#ifdef TZNAME_MAX
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700159#define MY_TZNAME_MAX TZNAME_MAX
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800160#endif /* defined TZNAME_MAX */
161#ifndef TZNAME_MAX
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700162#define MY_TZNAME_MAX 255
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800163#endif /* !defined TZNAME_MAX */
164
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700165/* XXX: This code should really use time64_t instead of time_t
166 * but we can't change it without re-generating the index
167 * file first with the correct data.
168 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800169struct state {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700170 int leapcnt;
171 int timecnt;
172 int typecnt;
173 int charcnt;
174 int goback;
175 int goahead;
176 time_t ats[TZ_MAX_TIMES];
177 unsigned char types[TZ_MAX_TIMES];
178 struct ttinfo ttis[TZ_MAX_TYPES];
179 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
180 (2 * (MY_TZNAME_MAX + 1)))];
181 struct lsinfo lsis[TZ_MAX_LEAPS];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800182};
183
184struct rule {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700185 int r_type; /* type of rule--see below */
186 int r_day; /* day number of rule */
187 int r_week; /* week number of rule */
188 int r_mon; /* month number of rule */
189 long r_time; /* transition time of rule */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800190};
191
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700192#define JULIAN_DAY 0 /* Jn - Julian day */
193#define DAY_OF_YEAR 1 /* n - day of year */
194#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 -0800195
196/*
197** Prototypes for static functions.
198*/
199
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700200/* NOTE: all internal functions assume that _tzLock() was already called */
201
Elliott Hughesd23af232012-10-17 16:30:47 -0700202static int __bionic_open_tzdata(const char*, int*);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700203static long detzcode P((const char * codep));
204static time_t detzcode64 P((const char * codep));
205static int differ_by_repeat P((time_t t1, time_t t0));
206static const char * getzname P((const char * strp));
207static const char * getqzname P((const char * strp, const int delim));
208static const char * getnum P((const char * strp, int * nump, int min,
209 int max));
210static const char * getsecs P((const char * strp, long * secsp));
211static const char * getoffset P((const char * strp, long * offsetp));
212static const char * getrule P((const char * strp, struct rule * rulep));
213static void gmtload P((struct state * sp));
214static struct tm * gmtsub P((const time_t * timep, long offset,
Elliott Hughesb989c9c2013-01-16 10:34:33 -0800215 struct tm * tmp, const struct state * sp)); // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700216static struct tm * localsub P((const time_t * timep, long offset,
Elliott Hughesb989c9c2013-01-16 10:34:33 -0800217 struct tm * tmp, const struct state * sp)); // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700218static int increment_overflow P((int * number, int delta));
219static int leaps_thru_end_of P((int y));
220static int long_increment_overflow P((long * number, int delta));
221static int long_normalize_overflow P((long * tensptr,
222 int * unitsptr, int base));
223static int normalize_overflow P((int * tensptr, int * unitsptr,
224 int base));
225static void settzname P((void));
226static time_t time1 P((struct tm * tmp,
227 struct tm * (*funcp) P((const time_t *,
Elliott Hughesb989c9c2013-01-16 10:34:33 -0800228 long, struct tm *, const struct state *)), // android-changed: added state*.
229 long offset, const struct state * sp)); // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700230static time_t time2 P((struct tm *tmp,
231 struct tm * (*funcp) P((const time_t *,
Elliott Hughesb989c9c2013-01-16 10:34:33 -0800232 long, struct tm*, const struct state *)), // android-changed: added state*.
233 long offset, int * okayp, const struct state * sp)); // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700234static time_t time2sub P((struct tm *tmp,
235 struct tm * (*funcp) P((const time_t *,
Elliott Hughesb989c9c2013-01-16 10:34:33 -0800236 long, struct tm*, const struct state *)), // android-changed: added state*.
237 long offset, int * okayp, int do_norm_secs, const struct state * sp)); // android-change: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700238static struct tm * timesub P((const time_t * timep, long offset,
239 const struct state * sp, struct tm * tmp));
240static int tmcomp P((const struct tm * atmp,
241 const struct tm * btmp));
242static time_t transtime P((time_t janfirst, int year,
243 const struct rule * rulep, long offset));
244static int tzload P((const char * name, struct state * sp,
245 int doextend));
246static int tzparse P((const char * name, struct state * sp,
247 int lastditch));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800248
249#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700250static struct state * lclptr;
251static struct state * gmtptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800252#endif /* defined ALL_STATE */
253
254#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700255static struct state lclmem;
256static struct state gmtmem;
257#define lclptr (&lclmem)
258#define gmtptr (&gmtmem)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800259#endif /* State Farm */
260
261#ifndef TZ_STRLEN_MAX
262#define TZ_STRLEN_MAX 255
263#endif /* !defined TZ_STRLEN_MAX */
264
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700265static char lcl_TZname[TZ_STRLEN_MAX + 1];
266static int lcl_is_set;
267static int gmt_is_set;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800268
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700269char * tzname[2] = {
270 wildabbr,
271 wildabbr
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800272};
273
274/*
275** Section 4.12.3 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700276** Except for the strftime function, these functions [asctime,
277** ctime, gmtime, localtime] return values in one of two static
278** objects: a broken-down time structure and an array of char.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800279** Thanks to Paul Eggert for noting this.
280*/
281
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700282static struct tm tmGlobal;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800283
284#ifdef USG_COMPAT
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700285time_t timezone = 0;
286int daylight = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800287#endif /* defined USG_COMPAT */
288
289#ifdef ALTZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700290time_t altzone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800291#endif /* defined ALTZONE */
292
293static long
294detzcode(codep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700295const char * const codep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800296{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700297 register long result;
298 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800299
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700300 result = (codep[0] & 0x80) ? ~0L : 0;
301 for (i = 0; i < 4; ++i)
302 result = (result << 8) | (codep[i] & 0xff);
303 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800304}
305
306static time_t
307detzcode64(codep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700308const char * const codep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800309{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700310 register time_t result;
311 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800312
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700313 result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0;
314 for (i = 0; i < 8; ++i)
315 result = result * 256 + (codep[i] & 0xff);
316 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800317}
318
319static void
320settzname P((void))
321{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700322 register struct state * const sp = lclptr;
323 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800324
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700325 tzname[0] = wildabbr;
326 tzname[1] = wildabbr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800327#ifdef USG_COMPAT
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700328 daylight = 0;
329 timezone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800330#endif /* defined USG_COMPAT */
331#ifdef ALTZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700332 altzone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800333#endif /* defined ALTZONE */
334#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700335 if (sp == NULL) {
336 tzname[0] = tzname[1] = gmt;
337 return;
338 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800339#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700340 for (i = 0; i < sp->typecnt; ++i) {
341 register const struct ttinfo * const ttisp = &sp->ttis[i];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800342
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700343 tzname[ttisp->tt_isdst] =
344 &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800345#ifdef USG_COMPAT
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700346 if (ttisp->tt_isdst)
347 daylight = 1;
348 if (i == 0 || !ttisp->tt_isdst)
349 timezone = -(ttisp->tt_gmtoff);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800350#endif /* defined USG_COMPAT */
351#ifdef ALTZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700352 if (i == 0 || ttisp->tt_isdst)
353 altzone = -(ttisp->tt_gmtoff);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800354#endif /* defined ALTZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700355 }
356 /*
357 ** And to get the latest zone names into tzname. . .
358 */
359 for (i = 0; i < sp->timecnt; ++i) {
360 register const struct ttinfo * const ttisp =
361 &sp->ttis[
362 sp->types[i]];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800363
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700364 tzname[ttisp->tt_isdst] =
365 &sp->chars[ttisp->tt_abbrind];
366 }
367 /*
368 ** Finally, scrub the abbreviations.
369 ** First, replace bogus characters.
370 */
371 for (i = 0; i < sp->charcnt; ++i)
372 if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
373 sp->chars[i] = TZ_ABBR_ERR_CHAR;
374 /*
375 ** Second, truncate long abbreviations.
376 */
377 for (i = 0; i < sp->typecnt; ++i) {
378 register const struct ttinfo * const ttisp = &sp->ttis[i];
379 register char * cp = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800380
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700381 if (strlen(cp) > TZ_ABBR_MAX_LEN &&
382 strcmp(cp, GRANDPARENTED) != 0)
383 *(cp + TZ_ABBR_MAX_LEN) = '\0';
384 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800385}
386
387static int
388differ_by_repeat(t1, t0)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700389const time_t t1;
390const time_t t0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800391{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700392 if (TYPE_INTEGRAL(time_t) &&
393 TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
394 return 0;
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700395#if SECSPERREPEAT_BITS <= 32 /* to avoid compiler warning (condition is always false) */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800396 return (t1 - t0) == SECSPERREPEAT;
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700397#else
398 return 0;
399#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800400}
401
402static int toint(unsigned char *s) {
403 return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
404}
405
406static int
407tzload(name, sp, doextend)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700408register const char * name;
409register struct state * const sp;
410register const int doextend;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800411{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700412 register const char * p;
413 register int i;
414 register int fid;
415 register int stored;
416 register int nread;
417 union {
418 struct tzhead tzhead;
419 char buf[2 * sizeof(struct tzhead) +
420 2 * sizeof *sp +
421 4 * TZ_MAX_TIMES];
422 } u;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800423 int toread = sizeof u.buf;
424
425 if (name == NULL && (name = TZDEFAULT) == NULL) {
426 XLOG(("tzload: null 'name' parameter\n" ));
427 return -1;
428 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700429 {
430 register int doaccess;
431 /*
432 ** Section 4.9.1 of the C standard says that
433 ** "FILENAME_MAX expands to an integral constant expression
434 ** that is the size needed for an array of char large enough
435 ** to hold the longest file name string that the implementation
436 ** guarantees can be opened."
437 */
438 char fullname[FILENAME_MAX + 1];
439 char *origname = (char*) name;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800440
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700441 if (name[0] == ':')
442 ++name;
443 doaccess = name[0] == '/';
444 if (!doaccess) {
445 if ((p = TZDIR) == NULL) {
446 XLOG(("tzload: null TZDIR macro ?\n" ));
447 return -1;
448 }
449 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) {
450 XLOG(( "tzload: path too long: %s/%s\n", p, name ));
451 return -1;
452 }
453 (void) strcpy(fullname, p);
454 (void) strcat(fullname, "/");
455 (void) strcat(fullname, name);
456 /*
457 ** Set doaccess if '.' (as in "../") shows up in name.
458 */
459 if (strchr(name, '.') != NULL)
460 doaccess = TRUE;
461 name = fullname;
462 }
463 if (doaccess && access(name, R_OK) != 0) {
464 XLOG(( "tzload: could not find '%s'\n", name ));
465 return -1;
466 }
467 if ((fid = open(name, OPEN_MODE)) == -1) {
Elliott Hughesd23af232012-10-17 16:30:47 -0700468 fid = __bionic_open_tzdata(origname, &toread);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800469 if (fid < 0) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800470 return -1;
471 }
472 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700473 }
474 nread = read(fid, u.buf, toread);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800475 if (close(fid) < 0 || nread <= 0) {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700476 XLOG(( "tzload: could not read content of '%s'\n", DATAFILE ));
477 return -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800478 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700479 for (stored = 4; stored <= 8; stored *= 2) {
480 int ttisstdcnt;
481 int ttisgmtcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800482
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700483 ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
484 ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
485 sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
486 sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
487 sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
488 sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
489 p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
490 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
491 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
492 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
493 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
494 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
495 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
496 return -1;
497 if (nread - (p - u.buf) <
498 sp->timecnt * stored + /* ats */
499 sp->timecnt + /* types */
500 sp->typecnt * 6 + /* ttinfos */
501 sp->charcnt + /* chars */
502 sp->leapcnt * (stored + 4) + /* lsinfos */
503 ttisstdcnt + /* ttisstds */
504 ttisgmtcnt) /* ttisgmts */
505 return -1;
506 for (i = 0; i < sp->timecnt; ++i) {
507 sp->ats[i] = (stored == 4) ?
508 detzcode(p) : detzcode64(p);
509 p += stored;
510 }
511 for (i = 0; i < sp->timecnt; ++i) {
512 sp->types[i] = (unsigned char) *p++;
513 if (sp->types[i] >= sp->typecnt)
514 return -1;
515 }
516 for (i = 0; i < sp->typecnt; ++i) {
517 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800518
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700519 ttisp = &sp->ttis[i];
520 ttisp->tt_gmtoff = detzcode(p);
521 p += 4;
522 ttisp->tt_isdst = (unsigned char) *p++;
523 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
524 return -1;
525 ttisp->tt_abbrind = (unsigned char) *p++;
526 if (ttisp->tt_abbrind < 0 ||
527 ttisp->tt_abbrind > sp->charcnt)
528 return -1;
529 }
530 for (i = 0; i < sp->charcnt; ++i)
531 sp->chars[i] = *p++;
532 sp->chars[i] = '\0'; /* ensure '\0' at end */
533 for (i = 0; i < sp->leapcnt; ++i) {
534 register struct lsinfo * lsisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800535
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700536 lsisp = &sp->lsis[i];
537 lsisp->ls_trans = (stored == 4) ?
538 detzcode(p) : detzcode64(p);
539 p += stored;
540 lsisp->ls_corr = detzcode(p);
541 p += 4;
542 }
543 for (i = 0; i < sp->typecnt; ++i) {
544 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800545
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700546 ttisp = &sp->ttis[i];
547 if (ttisstdcnt == 0)
548 ttisp->tt_ttisstd = FALSE;
549 else {
550 ttisp->tt_ttisstd = *p++;
551 if (ttisp->tt_ttisstd != TRUE &&
552 ttisp->tt_ttisstd != FALSE)
553 return -1;
554 }
555 }
556 for (i = 0; i < sp->typecnt; ++i) {
557 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800558
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700559 ttisp = &sp->ttis[i];
560 if (ttisgmtcnt == 0)
561 ttisp->tt_ttisgmt = FALSE;
562 else {
563 ttisp->tt_ttisgmt = *p++;
564 if (ttisp->tt_ttisgmt != TRUE &&
565 ttisp->tt_ttisgmt != FALSE)
566 return -1;
567 }
568 }
569 /*
570 ** Out-of-sort ats should mean we're running on a
571 ** signed time_t system but using a data file with
572 ** unsigned values (or vice versa).
573 */
574 for (i = 0; i < sp->timecnt - 2; ++i)
575 if (sp->ats[i] > sp->ats[i + 1]) {
576 ++i;
577 if (TYPE_SIGNED(time_t)) {
578 /*
579 ** Ignore the end (easy).
580 */
581 sp->timecnt = i;
582 } else {
583 /*
584 ** Ignore the beginning (harder).
585 */
586 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800587
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700588 for (j = 0; j + i < sp->timecnt; ++j) {
589 sp->ats[j] = sp->ats[j + i];
590 sp->types[j] = sp->types[j + i];
591 }
592 sp->timecnt = j;
593 }
594 break;
595 }
596 /*
597 ** If this is an old file, we're done.
598 */
599 if (u.tzhead.tzh_version[0] == '\0')
600 break;
601 nread -= p - u.buf;
602 for (i = 0; i < nread; ++i)
603 u.buf[i] = p[i];
604 /*
605 ** If this is a narrow integer time_t system, we're done.
606 */
607 if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
608 break;
609 }
610 if (doextend && nread > 2 &&
611 u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
612 sp->typecnt + 2 <= TZ_MAX_TYPES) {
613 struct state ts;
614 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800615
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700616 u.buf[nread - 1] = '\0';
617 result = tzparse(&u.buf[1], &ts, FALSE);
618 if (result == 0 && ts.typecnt == 2 &&
619 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
620 for (i = 0; i < 2; ++i)
621 ts.ttis[i].tt_abbrind +=
622 sp->charcnt;
623 for (i = 0; i < ts.charcnt; ++i)
624 sp->chars[sp->charcnt++] =
625 ts.chars[i];
626 i = 0;
627 while (i < ts.timecnt &&
628 ts.ats[i] <=
629 sp->ats[sp->timecnt - 1])
630 ++i;
631 while (i < ts.timecnt &&
632 sp->timecnt < TZ_MAX_TIMES) {
633 sp->ats[sp->timecnt] =
634 ts.ats[i];
635 sp->types[sp->timecnt] =
636 sp->typecnt +
637 ts.types[i];
638 ++sp->timecnt;
639 ++i;
640 }
641 sp->ttis[sp->typecnt++] = ts.ttis[0];
642 sp->ttis[sp->typecnt++] = ts.ttis[1];
643 }
644 }
645 i = 2 * YEARSPERREPEAT;
646 sp->goback = sp->goahead = sp->timecnt > i;
647 sp->goback &= sp->types[i] == sp->types[0] &&
648 differ_by_repeat(sp->ats[i], sp->ats[0]);
649 sp->goahead &=
650 sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
651 differ_by_repeat(sp->ats[sp->timecnt - 1],
652 sp->ats[sp->timecnt - 1 - i]);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800653 XLOG(( "tzload: load ok !!\n" ));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700654 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800655}
656
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700657static const int mon_lengths[2][MONSPERYEAR] = {
658 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
659 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800660};
661
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700662static const int year_lengths[2] = {
663 DAYSPERNYEAR, DAYSPERLYEAR
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800664};
665
666/*
667** Given a pointer into a time zone string, scan until a character that is not
668** a valid character in a zone name is found. Return a pointer to that
669** character.
670*/
671
672static const char *
673getzname(strp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700674register const char * strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800675{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700676 register char c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800677
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700678 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
679 c != '+')
680 ++strp;
681 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800682}
683
684/*
685** Given a pointer into an extended time zone string, scan until the ending
686** delimiter of the zone name is located. Return a pointer to the delimiter.
687**
688** As with getzname above, the legal character set is actually quite
689** restricted, with other characters producing undefined results.
690** We don't do any checking here; checking is done later in common-case code.
691*/
692
693static const char *
694getqzname(register const char *strp, const int delim)
695{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700696 register int c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800697
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700698 while ((c = *strp) != '\0' && c != delim)
699 ++strp;
700 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800701}
702
703/*
704** Given a pointer into a time zone string, extract a number from that string.
705** Check that the number is within a specified range; if it is not, return
706** NULL.
707** Otherwise, return a pointer to the first character not part of the number.
708*/
709
710static const char *
711getnum(strp, nump, min, max)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700712register const char * strp;
713int * const nump;
714const int min;
715const int max;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800716{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700717 register char c;
718 register int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800719
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700720 if (strp == NULL || !is_digit(c = *strp))
721 return NULL;
722 num = 0;
723 do {
724 num = num * 10 + (c - '0');
725 if (num > max)
726 return NULL; /* illegal value */
727 c = *++strp;
728 } while (is_digit(c));
729 if (num < min)
730 return NULL; /* illegal value */
731 *nump = num;
732 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800733}
734
735/*
736** Given a pointer into a time zone string, extract a number of seconds,
737** in hh[:mm[:ss]] form, from the string.
738** If any error occurs, return NULL.
739** Otherwise, return a pointer to the first character not part of the number
740** of seconds.
741*/
742
743static const char *
744getsecs(strp, secsp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700745register const char * strp;
746long * const secsp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800747{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700748 int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800749
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700750 /*
751 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
752 ** "M10.4.6/26", which does not conform to Posix,
753 ** but which specifies the equivalent of
754 ** ``02:00 on the first Sunday on or after 23 Oct''.
755 */
756 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
757 if (strp == NULL)
758 return NULL;
759 *secsp = num * (long) SECSPERHOUR;
760 if (*strp == ':') {
761 ++strp;
762 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
763 if (strp == NULL)
764 return NULL;
765 *secsp += num * SECSPERMIN;
766 if (*strp == ':') {
767 ++strp;
768 /* `SECSPERMIN' allows for leap seconds. */
769 strp = getnum(strp, &num, 0, SECSPERMIN);
770 if (strp == NULL)
771 return NULL;
772 *secsp += num;
773 }
774 }
775 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800776}
777
778/*
779** Given a pointer into a time zone string, extract an offset, in
780** [+-]hh[:mm[:ss]] form, from the string.
781** If any error occurs, return NULL.
782** Otherwise, return a pointer to the first character not part of the time.
783*/
784
785static const char *
786getoffset(strp, offsetp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700787register const char * strp;
788long * const offsetp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800789{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700790 register int neg = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800791
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700792 if (*strp == '-') {
793 neg = 1;
794 ++strp;
795 } else if (*strp == '+')
796 ++strp;
797 strp = getsecs(strp, offsetp);
798 if (strp == NULL)
799 return NULL; /* illegal time */
800 if (neg)
801 *offsetp = -*offsetp;
802 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800803}
804
805/*
806** Given a pointer into a time zone string, extract a rule in the form
807** date[/time]. See POSIX section 8 for the format of "date" and "time".
808** If a valid rule is not found, return NULL.
809** Otherwise, return a pointer to the first character not part of the rule.
810*/
811
812static const char *
813getrule(strp, rulep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700814const char * strp;
815register struct rule * const rulep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800816{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700817 if (*strp == 'J') {
818 /*
819 ** Julian day.
820 */
821 rulep->r_type = JULIAN_DAY;
822 ++strp;
823 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
824 } else if (*strp == 'M') {
825 /*
826 ** Month, week, day.
827 */
828 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
829 ++strp;
830 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
831 if (strp == NULL)
832 return NULL;
833 if (*strp++ != '.')
834 return NULL;
835 strp = getnum(strp, &rulep->r_week, 1, 5);
836 if (strp == NULL)
837 return NULL;
838 if (*strp++ != '.')
839 return NULL;
840 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
841 } else if (is_digit(*strp)) {
842 /*
843 ** Day of year.
844 */
845 rulep->r_type = DAY_OF_YEAR;
846 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
847 } else return NULL; /* invalid format */
848 if (strp == NULL)
849 return NULL;
850 if (*strp == '/') {
851 /*
852 ** Time specified.
853 */
854 ++strp;
855 strp = getsecs(strp, &rulep->r_time);
856 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
857 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800858}
859
860/*
861** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
862** year, a rule, and the offset from UTC at the time that rule takes effect,
863** calculate the Epoch-relative time that rule takes effect.
864*/
865
866static time_t
867transtime(janfirst, year, rulep, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700868const time_t janfirst;
869const int year;
870register const struct rule * const rulep;
871const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800872{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700873 register int leapyear;
874 register time_t value;
875 register int i;
876 int d, m1, yy0, yy1, yy2, dow;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800877
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700878 INITIALIZE(value);
879 leapyear = isleap(year);
880 switch (rulep->r_type) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800881
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700882 case JULIAN_DAY:
883 /*
884 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
885 ** years.
886 ** In non-leap years, or if the day number is 59 or less, just
887 ** add SECSPERDAY times the day number-1 to the time of
888 ** January 1, midnight, to get the day.
889 */
890 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
891 if (leapyear && rulep->r_day >= 60)
892 value += SECSPERDAY;
893 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800894
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700895 case DAY_OF_YEAR:
896 /*
897 ** n - day of year.
898 ** Just add SECSPERDAY times the day number to the time of
899 ** January 1, midnight, to get the day.
900 */
901 value = janfirst + rulep->r_day * SECSPERDAY;
902 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800903
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700904 case MONTH_NTH_DAY_OF_WEEK:
905 /*
906 ** Mm.n.d - nth "dth day" of month m.
907 */
908 value = janfirst;
909 for (i = 0; i < rulep->r_mon - 1; ++i)
910 value += mon_lengths[leapyear][i] * SECSPERDAY;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800911
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700912 /*
913 ** Use Zeller's Congruence to get day-of-week of first day of
914 ** month.
915 */
916 m1 = (rulep->r_mon + 9) % 12 + 1;
917 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
918 yy1 = yy0 / 100;
919 yy2 = yy0 % 100;
920 dow = ((26 * m1 - 2) / 10 +
921 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
922 if (dow < 0)
923 dow += DAYSPERWEEK;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800924
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700925 /*
926 ** "dow" is the day-of-week of the first day of the month. Get
927 ** the day-of-month (zero-origin) of the first "dow" day of the
928 ** month.
929 */
930 d = rulep->r_day - dow;
931 if (d < 0)
932 d += DAYSPERWEEK;
933 for (i = 1; i < rulep->r_week; ++i) {
934 if (d + DAYSPERWEEK >=
935 mon_lengths[leapyear][rulep->r_mon - 1])
936 break;
937 d += DAYSPERWEEK;
938 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800939
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700940 /*
941 ** "d" is the day-of-month (zero-origin) of the day we want.
942 */
943 value += d * SECSPERDAY;
944 break;
945 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800946
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700947 /*
948 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
949 ** question. To get the Epoch-relative time of the specified local
950 ** time on that day, add the transition time and the current offset
951 ** from UTC.
952 */
953 return value + rulep->r_time + offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800954}
955
956/*
957** Given a POSIX section 8-style TZ string, fill in the rule tables as
958** appropriate.
959*/
960
961static int
962tzparse(name, sp, lastditch)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700963const char * name;
964register struct state * const sp;
965const int lastditch;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800966{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700967 const char * stdname;
968 const char * dstname;
969 size_t stdlen;
970 size_t dstlen;
971 long stdoffset;
972 long dstoffset;
973 register time_t * atp;
974 register unsigned char * typep;
975 register char * cp;
976 register int load_result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800977
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700978 INITIALIZE(dstname);
979 stdname = name;
980 if (lastditch) {
981 stdlen = strlen(name); /* length of standard zone name */
982 name += stdlen;
983 if (stdlen >= sizeof sp->chars)
984 stdlen = (sizeof sp->chars) - 1;
985 stdoffset = 0;
986 } else {
987 if (*name == '<') {
988 name++;
989 stdname = name;
990 name = getqzname(name, '>');
991 if (*name != '>')
992 return (-1);
993 stdlen = name - stdname;
994 name++;
995 } else {
996 name = getzname(name);
997 stdlen = name - stdname;
998 }
999 if (*name == '\0')
1000 return -1;
1001 name = getoffset(name, &stdoffset);
1002 if (name == NULL)
1003 return -1;
1004 }
1005 load_result = tzload(TZDEFRULES, sp, FALSE);
1006 if (load_result != 0)
1007 sp->leapcnt = 0; /* so, we're off a little */
1008 sp->timecnt = 0;
1009 if (*name != '\0') {
1010 if (*name == '<') {
1011 dstname = ++name;
1012 name = getqzname(name, '>');
1013 if (*name != '>')
1014 return -1;
1015 dstlen = name - dstname;
1016 name++;
1017 } else {
1018 dstname = name;
1019 name = getzname(name);
1020 dstlen = name - dstname; /* length of DST zone name */
1021 }
1022 if (*name != '\0' && *name != ',' && *name != ';') {
1023 name = getoffset(name, &dstoffset);
1024 if (name == NULL)
1025 return -1;
1026 } else dstoffset = stdoffset - SECSPERHOUR;
1027 if (*name == '\0' && load_result != 0)
1028 name = TZDEFRULESTRING;
1029 if (*name == ',' || *name == ';') {
1030 struct rule start;
1031 struct rule end;
1032 register int year;
1033 register time_t janfirst;
1034 time_t starttime;
1035 time_t endtime;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001036
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001037 ++name;
1038 if ((name = getrule(name, &start)) == NULL)
1039 return -1;
1040 if (*name++ != ',')
1041 return -1;
1042 if ((name = getrule(name, &end)) == NULL)
1043 return -1;
1044 if (*name != '\0')
1045 return -1;
1046 sp->typecnt = 2; /* standard time and DST */
1047 /*
1048 ** Two transitions per year, from EPOCH_YEAR forward.
1049 */
1050 sp->ttis[0].tt_gmtoff = -dstoffset;
1051 sp->ttis[0].tt_isdst = 1;
1052 sp->ttis[0].tt_abbrind = stdlen + 1;
1053 sp->ttis[1].tt_gmtoff = -stdoffset;
1054 sp->ttis[1].tt_isdst = 0;
1055 sp->ttis[1].tt_abbrind = 0;
1056 atp = sp->ats;
1057 typep = sp->types;
1058 janfirst = 0;
1059 for (year = EPOCH_YEAR;
1060 sp->timecnt + 2 <= TZ_MAX_TIMES;
1061 ++year) {
1062 time_t newfirst;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001063
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001064 starttime = transtime(janfirst, year, &start,
1065 stdoffset);
1066 endtime = transtime(janfirst, year, &end,
1067 dstoffset);
1068 if (starttime > endtime) {
1069 *atp++ = endtime;
1070 *typep++ = 1; /* DST ends */
1071 *atp++ = starttime;
1072 *typep++ = 0; /* DST begins */
1073 } else {
1074 *atp++ = starttime;
1075 *typep++ = 0; /* DST begins */
1076 *atp++ = endtime;
1077 *typep++ = 1; /* DST ends */
1078 }
1079 sp->timecnt += 2;
1080 newfirst = janfirst;
1081 newfirst += year_lengths[isleap(year)] *
1082 SECSPERDAY;
1083 if (newfirst <= janfirst)
1084 break;
1085 janfirst = newfirst;
1086 }
1087 } else {
1088 register long theirstdoffset;
1089 register long theirdstoffset;
1090 register long theiroffset;
1091 register int isdst;
1092 register int i;
1093 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001094
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001095 if (*name != '\0')
1096 return -1;
1097 /*
1098 ** Initial values of theirstdoffset and theirdstoffset.
1099 */
1100 theirstdoffset = 0;
1101 for (i = 0; i < sp->timecnt; ++i) {
1102 j = sp->types[i];
1103 if (!sp->ttis[j].tt_isdst) {
1104 theirstdoffset =
1105 -sp->ttis[j].tt_gmtoff;
1106 break;
1107 }
1108 }
1109 theirdstoffset = 0;
1110 for (i = 0; i < sp->timecnt; ++i) {
1111 j = sp->types[i];
1112 if (sp->ttis[j].tt_isdst) {
1113 theirdstoffset =
1114 -sp->ttis[j].tt_gmtoff;
1115 break;
1116 }
1117 }
1118 /*
1119 ** Initially we're assumed to be in standard time.
1120 */
1121 isdst = FALSE;
1122 theiroffset = theirstdoffset;
1123 /*
1124 ** Now juggle transition times and types
1125 ** tracking offsets as you do.
1126 */
1127 for (i = 0; i < sp->timecnt; ++i) {
1128 j = sp->types[i];
1129 sp->types[i] = sp->ttis[j].tt_isdst;
1130 if (sp->ttis[j].tt_ttisgmt) {
1131 /* No adjustment to transition time */
1132 } else {
1133 /*
1134 ** If summer time is in effect, and the
1135 ** transition time was not specified as
1136 ** standard time, add the summer time
1137 ** offset to the transition time;
1138 ** otherwise, add the standard time
1139 ** offset to the transition time.
1140 */
1141 /*
1142 ** Transitions from DST to DDST
1143 ** will effectively disappear since
1144 ** POSIX provides for only one DST
1145 ** offset.
1146 */
1147 if (isdst && !sp->ttis[j].tt_ttisstd) {
1148 sp->ats[i] += dstoffset -
1149 theirdstoffset;
1150 } else {
1151 sp->ats[i] += stdoffset -
1152 theirstdoffset;
1153 }
1154 }
1155 theiroffset = -sp->ttis[j].tt_gmtoff;
1156 if (sp->ttis[j].tt_isdst)
1157 theirdstoffset = theiroffset;
1158 else theirstdoffset = theiroffset;
1159 }
1160 /*
1161 ** Finally, fill in ttis.
1162 ** ttisstd and ttisgmt need not be handled.
1163 */
1164 sp->ttis[0].tt_gmtoff = -stdoffset;
1165 sp->ttis[0].tt_isdst = FALSE;
1166 sp->ttis[0].tt_abbrind = 0;
1167 sp->ttis[1].tt_gmtoff = -dstoffset;
1168 sp->ttis[1].tt_isdst = TRUE;
1169 sp->ttis[1].tt_abbrind = stdlen + 1;
1170 sp->typecnt = 2;
1171 }
1172 } else {
1173 dstlen = 0;
1174 sp->typecnt = 1; /* only standard time */
1175 sp->timecnt = 0;
1176 sp->ttis[0].tt_gmtoff = -stdoffset;
1177 sp->ttis[0].tt_isdst = 0;
1178 sp->ttis[0].tt_abbrind = 0;
1179 }
1180 sp->charcnt = stdlen + 1;
1181 if (dstlen != 0)
1182 sp->charcnt += dstlen + 1;
1183 if ((size_t) sp->charcnt > sizeof sp->chars)
1184 return -1;
1185 cp = sp->chars;
1186 (void) strncpy(cp, stdname, stdlen);
1187 cp += stdlen;
1188 *cp++ = '\0';
1189 if (dstlen != 0) {
1190 (void) strncpy(cp, dstname, dstlen);
1191 *(cp + dstlen) = '\0';
1192 }
1193 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001194}
1195
1196static void
1197gmtload(sp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001198struct state * const sp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001199{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001200 if (tzload(gmt, sp, TRUE) != 0)
1201 (void) tzparse(gmt, sp, TRUE);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001202}
1203
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001204static void
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001205tzsetwall P((void))
1206{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001207 if (lcl_is_set < 0)
1208 return;
1209 lcl_is_set = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001210
1211#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001212 if (lclptr == NULL) {
1213 lclptr = (struct state *) malloc(sizeof *lclptr);
1214 if (lclptr == NULL) {
1215 settzname(); /* all we can do */
1216 return;
1217 }
1218 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001219#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001220 if (tzload((char *) NULL, lclptr, TRUE) != 0)
1221 gmtload(lclptr);
1222 settzname();
1223}
1224
1225static void
1226tzset_locked P((void))
1227{
1228 register const char * name = NULL;
1229 static char buf[PROP_VALUE_MAX];
1230
1231 name = getenv("TZ");
1232
1233 // try the "persist.sys.timezone" system property first
1234 if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0)
1235 name = buf;
1236
1237 if (name == NULL) {
1238 tzsetwall();
1239 return;
1240 }
1241
1242 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
1243 return;
1244 lcl_is_set = strlen(name) < sizeof lcl_TZname;
1245 if (lcl_is_set)
1246 (void) strcpy(lcl_TZname, name);
1247
1248#ifdef ALL_STATE
1249 if (lclptr == NULL) {
1250 lclptr = (struct state *) malloc(sizeof *lclptr);
1251 if (lclptr == NULL) {
1252 settzname(); /* all we can do */
1253 return;
1254 }
1255 }
1256#endif /* defined ALL_STATE */
1257 if (*name == '\0') {
1258 /*
1259 ** User wants it fast rather than right.
1260 */
1261 lclptr->leapcnt = 0; /* so, we're off a little */
1262 lclptr->timecnt = 0;
1263 lclptr->typecnt = 0;
1264 lclptr->ttis[0].tt_isdst = 0;
1265 lclptr->ttis[0].tt_gmtoff = 0;
1266 lclptr->ttis[0].tt_abbrind = 0;
1267 (void) strcpy(lclptr->chars, gmt);
1268 } else if (tzload(name, lclptr, TRUE) != 0)
1269 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
1270 (void) gmtload(lclptr);
1271 settzname();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001272}
1273
1274void
1275tzset P((void))
1276{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001277 _tzLock();
1278 tzset_locked();
1279 _tzUnlock();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001280}
1281
1282/*
1283** The easy way to behave "as if no library function calls" localtime
1284** is to not call it--so we drop its guts into "localsub", which can be
1285** freely called. (And no, the PANS doesn't require the above behavior--
1286** but it *is* desirable.)
1287**
1288** The unused offset argument is for the benefit of mktime variants.
1289*/
1290
1291/*ARGSUSED*/
1292static struct tm *
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001293localsub(timep, offset, tmp, sp) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001294const time_t * const timep;
1295const long offset;
1296struct tm * const tmp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001297const struct state * sp; // android-added: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001298{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001299 register const struct ttinfo * ttisp;
1300 register int i;
1301 register struct tm * result;
1302 const time_t t = *timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001303
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001304 // BEGIN android-changed: support user-supplied sp.
1305 if (sp == NULL) {
1306 sp = lclptr;
1307 }
1308 // END android-changed
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001309#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001310 if (sp == NULL)
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001311 return gmtsub(timep, offset, tmp, sp); // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001312#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001313 if ((sp->goback && t < sp->ats[0]) ||
1314 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1315 time_t newt = t;
1316 register time_t seconds;
1317 register time_t tcycles;
1318 register int_fast64_t icycles;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001319
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001320 if (t < sp->ats[0])
1321 seconds = sp->ats[0] - t;
1322 else seconds = t - sp->ats[sp->timecnt - 1];
1323 --seconds;
1324 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1325 ++tcycles;
1326 icycles = tcycles;
1327 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1328 return NULL;
1329 seconds = icycles;
1330 seconds *= YEARSPERREPEAT;
1331 seconds *= AVGSECSPERYEAR;
1332 if (t < sp->ats[0])
1333 newt += seconds;
1334 else newt -= seconds;
1335 if (newt < sp->ats[0] ||
1336 newt > sp->ats[sp->timecnt - 1])
1337 return NULL; /* "cannot happen" */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001338 result = localsub(&newt, offset, tmp, sp); // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001339 if (result == tmp) {
1340 register time_t newy;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001341
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001342 newy = tmp->tm_year;
1343 if (t < sp->ats[0])
1344 newy -= icycles * YEARSPERREPEAT;
1345 else newy += icycles * YEARSPERREPEAT;
1346 tmp->tm_year = newy;
1347 if (tmp->tm_year != newy)
1348 return NULL;
1349 }
1350 return result;
1351 }
1352 if (sp->timecnt == 0 || t < sp->ats[0]) {
1353 i = 0;
1354 while (sp->ttis[i].tt_isdst)
1355 if (++i >= sp->typecnt) {
1356 i = 0;
1357 break;
1358 }
1359 } else {
1360 register int lo = 1;
1361 register int hi = sp->timecnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001362
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001363 while (lo < hi) {
1364 register int mid = (lo + hi) >> 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001365
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001366 if (t < sp->ats[mid])
1367 hi = mid;
1368 else lo = mid + 1;
1369 }
1370 i = (int) sp->types[lo - 1];
1371 }
1372 ttisp = &sp->ttis[i];
1373 /*
1374 ** To get (wrong) behavior that's compatible with System V Release 2.0
1375 ** you'd replace the statement below with
1376 ** t += ttisp->tt_gmtoff;
1377 ** timesub(&t, 0L, sp, tmp);
1378 */
1379 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1380 tmp->tm_isdst = ttisp->tt_isdst;
1381 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001382#ifdef TM_ZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001383 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001384#endif /* defined TM_ZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001385 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001386}
1387
1388struct tm *
1389localtime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001390const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001391{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001392 return localtime_r(timep, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001393}
1394
1395/*
1396** Re-entrant version of localtime.
1397*/
1398
1399struct tm *
1400localtime_r(timep, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001401const time_t * const timep;
1402struct tm * tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001403{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001404 struct tm* result;
1405
1406 _tzLock();
1407 tzset_locked();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001408 result = localsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001409 _tzUnlock();
1410
1411 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001412}
1413
1414/*
1415** gmtsub is to gmtime as localsub is to localtime.
1416*/
1417
1418static struct tm *
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001419gmtsub(timep, offset, tmp, sp) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001420const time_t * const timep;
1421const long offset;
1422struct tm * const tmp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001423const struct state * sp; // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001424{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001425 register struct tm * result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001426
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001427 (void) sp; // android-added: unused.
1428
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001429 if (!gmt_is_set) {
1430 gmt_is_set = TRUE;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001431#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001432 gmtptr = (struct state *) malloc(sizeof *gmtptr);
1433 if (gmtptr != NULL)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001434#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001435 gmtload(gmtptr);
1436 }
1437 result = timesub(timep, offset, gmtptr, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001438#ifdef TM_ZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001439 /*
1440 ** Could get fancy here and deliver something such as
1441 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
1442 ** but this is no time for a treasure hunt.
1443 */
1444 if (offset != 0)
1445 tmp->TM_ZONE = wildabbr;
1446 else {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001447#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001448 if (gmtptr == NULL)
1449 tmp->TM_ZONE = gmt;
1450 else tmp->TM_ZONE = gmtptr->chars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001451#endif /* defined ALL_STATE */
1452#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001453 tmp->TM_ZONE = gmtptr->chars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001454#endif /* State Farm */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001455 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001456#endif /* defined TM_ZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001457 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001458}
1459
1460struct tm *
1461gmtime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001462const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001463{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001464 return gmtime_r(timep, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001465}
1466
1467/*
1468* Re-entrant version of gmtime.
1469*/
1470
1471struct tm *
1472gmtime_r(timep, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001473const time_t * const timep;
1474struct tm * tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001475{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001476 struct tm* result;
1477
1478 _tzLock();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001479 result = gmtsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001480 _tzUnlock();
1481
1482 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001483}
1484
1485#ifdef STD_INSPIRED
David 'Digit' Turner6481b912010-12-06 12:23:16 +01001486#if 0 /* disabled because there is no good documentation for this function */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001487struct tm *
1488offtime(timep, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001489const time_t * const timep;
1490const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001491{
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001492 return gmtsub(timep, offset, &tmGlobal, NULL); // android-changed: extra parameter.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001493}
David 'Digit' Turner6481b912010-12-06 12:23:16 +01001494#endif /* 0 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001495#endif /* defined STD_INSPIRED */
1496
1497/*
1498** Return the number of leap years through the end of the given year
1499** where, to make the math easy, the answer for year zero is defined as zero.
1500*/
1501
1502static int
1503leaps_thru_end_of(y)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001504register const int y;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001505{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001506 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1507 -(leaps_thru_end_of(-(y + 1)) + 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001508}
1509
1510static struct tm *
1511timesub(timep, offset, sp, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001512const time_t * const timep;
1513const long offset;
1514register const struct state * const sp;
1515register struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001516{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001517 register const struct lsinfo * lp;
1518 register time_t tdays;
1519 register int idays; /* unsigned would be so 2003 */
1520 register long rem;
1521 int y;
1522 register const int * ip;
1523 register long corr;
1524 register int hit;
1525 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001526
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001527 corr = 0;
1528 hit = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001529#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001530 i = (sp == NULL) ? 0 : sp->leapcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001531#endif /* defined ALL_STATE */
1532#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001533 i = sp->leapcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001534#endif /* State Farm */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001535 while (--i >= 0) {
1536 lp = &sp->lsis[i];
1537 if (*timep >= lp->ls_trans) {
1538 if (*timep == lp->ls_trans) {
1539 hit = ((i == 0 && lp->ls_corr > 0) ||
1540 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1541 if (hit)
1542 while (i > 0 &&
1543 sp->lsis[i].ls_trans ==
1544 sp->lsis[i - 1].ls_trans + 1 &&
1545 sp->lsis[i].ls_corr ==
1546 sp->lsis[i - 1].ls_corr + 1) {
1547 ++hit;
1548 --i;
1549 }
1550 }
1551 corr = lp->ls_corr;
1552 break;
1553 }
1554 }
1555 y = EPOCH_YEAR;
1556 tdays = *timep / SECSPERDAY;
1557 rem = *timep - tdays * SECSPERDAY;
1558 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1559 int newy;
1560 register time_t tdelta;
1561 register int idelta;
1562 register int leapdays;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001563
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001564 tdelta = tdays / DAYSPERLYEAR;
1565 idelta = tdelta;
1566 if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
1567 return NULL;
1568 if (idelta == 0)
1569 idelta = (tdays < 0) ? -1 : 1;
1570 newy = y;
1571 if (increment_overflow(&newy, idelta))
1572 return NULL;
1573 leapdays = leaps_thru_end_of(newy - 1) -
1574 leaps_thru_end_of(y - 1);
1575 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1576 tdays -= leapdays;
1577 y = newy;
1578 }
1579 {
1580 register long seconds;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001581
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001582 seconds = tdays * SECSPERDAY + 0.5;
1583 tdays = seconds / SECSPERDAY;
1584 rem += seconds - tdays * SECSPERDAY;
1585 }
1586 /*
1587 ** Given the range, we can now fearlessly cast...
1588 */
1589 idays = tdays;
1590 rem += offset - corr;
1591 while (rem < 0) {
1592 rem += SECSPERDAY;
1593 --idays;
1594 }
1595 while (rem >= SECSPERDAY) {
1596 rem -= SECSPERDAY;
1597 ++idays;
1598 }
1599 while (idays < 0) {
1600 if (increment_overflow(&y, -1))
1601 return NULL;
1602 idays += year_lengths[isleap(y)];
1603 }
1604 while (idays >= year_lengths[isleap(y)]) {
1605 idays -= year_lengths[isleap(y)];
1606 if (increment_overflow(&y, 1))
1607 return NULL;
1608 }
1609 tmp->tm_year = y;
1610 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1611 return NULL;
1612 tmp->tm_yday = idays;
1613 /*
1614 ** The "extra" mods below avoid overflow problems.
1615 */
1616 tmp->tm_wday = EPOCH_WDAY +
1617 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
1618 (DAYSPERNYEAR % DAYSPERWEEK) +
1619 leaps_thru_end_of(y - 1) -
1620 leaps_thru_end_of(EPOCH_YEAR - 1) +
1621 idays;
1622 tmp->tm_wday %= DAYSPERWEEK;
1623 if (tmp->tm_wday < 0)
1624 tmp->tm_wday += DAYSPERWEEK;
1625 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1626 rem %= SECSPERHOUR;
1627 tmp->tm_min = (int) (rem / SECSPERMIN);
1628 /*
1629 ** A positive leap second requires a special
1630 ** representation. This uses "... ??:59:60" et seq.
1631 */
1632 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1633 ip = mon_lengths[isleap(y)];
1634 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1635 idays -= ip[tmp->tm_mon];
1636 tmp->tm_mday = (int) (idays + 1);
1637 tmp->tm_isdst = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001638#ifdef TM_GMTOFF
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001639 tmp->TM_GMTOFF = offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001640#endif /* defined TM_GMTOFF */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001641 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001642}
1643
1644char *
1645ctime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001646const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001647{
1648/*
1649** Section 4.12.3.2 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001650** The ctime function converts the calendar time pointed to by timer
1651** to local time in the form of a string. It is equivalent to
1652** asctime(localtime(timer))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001653*/
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001654 return asctime(localtime(timep));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001655}
1656
1657char *
1658ctime_r(timep, buf)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001659const time_t * const timep;
1660char * buf;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001661{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001662 struct tm mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001663
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001664 return asctime_r(localtime_r(timep, &mytm), buf);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001665}
1666
1667/*
1668** Adapted from code provided by Robert Elz, who writes:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001669** The "best" way to do mktime I think is based on an idea of Bob
1670** Kridle's (so its said...) from a long time ago.
1671** It does a binary search of the time_t space. Since time_t's are
1672** just 32 bits, its a max of 32 iterations (even at 64 bits it
1673** would still be very reasonable).
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001674*/
1675
1676#ifndef WRONG
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001677#define WRONG (-1)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001678#endif /* !defined WRONG */
1679
1680/*
1681** Simplified normalize logic courtesy Paul Eggert.
1682*/
1683
1684static int
1685increment_overflow(number, delta)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001686int * number;
1687int delta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001688{
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001689 unsigned number0 = (unsigned)*number;
1690 unsigned number1 = (unsigned)(number0 + delta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001691
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001692 *number = (int)number1;
1693
1694 if (delta >= 0) {
1695 return ((int)number1 < (int)number0);
1696 } else {
1697 return ((int)number1 > (int)number0);
1698 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001699}
1700
1701static int
1702long_increment_overflow(number, delta)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001703long * number;
1704int delta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001705{
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001706 unsigned long number0 = (unsigned long)*number;
1707 unsigned long number1 = (unsigned long)(number0 + delta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001708
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001709 *number = (long)number1;
1710
1711 if (delta >= 0) {
1712 return ((long)number1 < (long)number0);
1713 } else {
1714 return ((long)number1 > (long)number0);
1715 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001716}
1717
1718static int
1719normalize_overflow(tensptr, unitsptr, base)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001720int * const tensptr;
1721int * const unitsptr;
1722const int base;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001723{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001724 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001725
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001726 tensdelta = (*unitsptr >= 0) ?
1727 (*unitsptr / base) :
1728 (-1 - (-1 - *unitsptr) / base);
1729 *unitsptr -= tensdelta * base;
1730 return increment_overflow(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001731}
1732
1733static int
1734long_normalize_overflow(tensptr, unitsptr, base)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001735long * const tensptr;
1736int * const unitsptr;
1737const int base;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001738{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001739 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001740
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001741 tensdelta = (*unitsptr >= 0) ?
1742 (*unitsptr / base) :
1743 (-1 - (-1 - *unitsptr) / base);
1744 *unitsptr -= tensdelta * base;
1745 return long_increment_overflow(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001746}
1747
1748static int
1749tmcomp(atmp, btmp)
1750register const struct tm * const atmp;
1751register const struct tm * const btmp;
1752{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001753 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001754
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001755 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1756 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1757 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1758 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1759 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1760 result = atmp->tm_sec - btmp->tm_sec;
1761 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001762}
1763
1764static time_t
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001765time2sub(tmp, funcp, offset, okayp, do_norm_secs, sp) // android-changed: added sp
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001766struct tm * const tmp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001767struct tm * (* const funcp) P((const time_t*, long, struct tm*, const struct state*)); // android-changed: added state*
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001768const long offset;
1769int * const okayp;
1770const int do_norm_secs;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001771const struct state * sp; // android-changed: added sp
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001772{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001773 register int dir;
1774 register int i, j;
1775 register int saved_seconds;
1776 register long li;
1777 register time_t lo;
1778 register time_t hi;
1779 long y;
1780 time_t newt;
1781 time_t t;
1782 struct tm yourtm, mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001783
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001784 *okayp = FALSE;
1785 yourtm = *tmp;
1786 if (do_norm_secs) {
1787 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1788 SECSPERMIN))
1789 return WRONG;
1790 }
1791 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1792 return WRONG;
1793 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1794 return WRONG;
1795 y = yourtm.tm_year;
1796 if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
1797 return WRONG;
1798 /*
1799 ** Turn y into an actual year number for now.
1800 ** It is converted back to an offset from TM_YEAR_BASE later.
1801 */
1802 if (long_increment_overflow(&y, TM_YEAR_BASE))
1803 return WRONG;
1804 while (yourtm.tm_mday <= 0) {
1805 if (long_increment_overflow(&y, -1))
1806 return WRONG;
1807 li = y + (1 < yourtm.tm_mon);
1808 yourtm.tm_mday += year_lengths[isleap(li)];
1809 }
1810 while (yourtm.tm_mday > DAYSPERLYEAR) {
1811 li = y + (1 < yourtm.tm_mon);
1812 yourtm.tm_mday -= year_lengths[isleap(li)];
1813 if (long_increment_overflow(&y, 1))
1814 return WRONG;
1815 }
1816 for ( ; ; ) {
1817 i = mon_lengths[isleap(y)][yourtm.tm_mon];
1818 if (yourtm.tm_mday <= i)
1819 break;
1820 yourtm.tm_mday -= i;
1821 if (++yourtm.tm_mon >= MONSPERYEAR) {
1822 yourtm.tm_mon = 0;
1823 if (long_increment_overflow(&y, 1))
1824 return WRONG;
1825 }
1826 }
1827 if (long_increment_overflow(&y, -TM_YEAR_BASE))
1828 return WRONG;
1829 yourtm.tm_year = y;
1830 if (yourtm.tm_year != y)
1831 return WRONG;
1832 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
1833 saved_seconds = 0;
1834 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
1835 /*
1836 ** We can't set tm_sec to 0, because that might push the
1837 ** time below the minimum representable time.
1838 ** Set tm_sec to 59 instead.
1839 ** This assumes that the minimum representable time is
1840 ** not in the same minute that a leap second was deleted from,
1841 ** which is a safer assumption than using 58 would be.
1842 */
1843 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1844 return WRONG;
1845 saved_seconds = yourtm.tm_sec;
1846 yourtm.tm_sec = SECSPERMIN - 1;
1847 } else {
1848 saved_seconds = yourtm.tm_sec;
1849 yourtm.tm_sec = 0;
1850 }
1851 /*
1852 ** Do a binary search (this works whatever time_t's type is).
1853 */
1854 if (!TYPE_SIGNED(time_t)) {
1855 lo = 0;
1856 hi = lo - 1;
1857 } else if (!TYPE_INTEGRAL(time_t)) {
1858 if (sizeof(time_t) > sizeof(float))
1859 hi = (time_t) DBL_MAX;
1860 else hi = (time_t) FLT_MAX;
1861 lo = -hi;
1862 } else {
1863 lo = 1;
1864 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
1865 lo *= 2;
1866 hi = -(lo + 1);
1867 }
1868 for ( ; ; ) {
1869 t = lo / 2 + hi / 2;
1870 if (t < lo)
1871 t = lo;
1872 else if (t > hi)
1873 t = hi;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001874 if ((*funcp)(&t, offset, &mytm, sp) == NULL) { // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001875 /*
1876 ** Assume that t is too extreme to be represented in
1877 ** a struct tm; arrange things so that it is less
1878 ** extreme on the next pass.
1879 */
1880 dir = (t > 0) ? 1 : -1;
1881 } else dir = tmcomp(&mytm, &yourtm);
1882 if (dir != 0) {
1883 if (t == lo) {
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001884 if (t == TIME_T_MAX)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001885 return WRONG;
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001886 ++t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001887 ++lo;
1888 } else if (t == hi) {
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001889 if (t == TIME_T_MIN)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001890 return WRONG;
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001891 --t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001892 --hi;
1893 }
1894 if (lo > hi)
1895 return WRONG;
1896 if (dir > 0)
1897 hi = t;
1898 else lo = t;
1899 continue;
1900 }
1901 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1902 break;
1903 /*
1904 ** Right time, wrong type.
1905 ** Hunt for right time, right type.
1906 ** It's okay to guess wrong since the guess
1907 ** gets checked.
1908 */
1909 /*
1910 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1911 */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001912 // BEGIN android-changed: support user-supplied sp
1913 if (sp == NULL) {
1914 sp = (const struct state *)
1915 (((void *) funcp == (void *) localsub) ?
1916 lclptr : gmtptr);
1917 }
1918 // END android-changed
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001919#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001920 if (sp == NULL)
1921 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001922#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001923 for (i = sp->typecnt - 1; i >= 0; --i) {
1924 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1925 continue;
1926 for (j = sp->typecnt - 1; j >= 0; --j) {
1927 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1928 continue;
1929 newt = t + sp->ttis[j].tt_gmtoff -
1930 sp->ttis[i].tt_gmtoff;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001931 if ((*funcp)(&newt, offset, &mytm, sp) == NULL) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001932 continue;
1933 if (tmcomp(&mytm, &yourtm) != 0)
1934 continue;
1935 if (mytm.tm_isdst != yourtm.tm_isdst)
1936 continue;
1937 /*
1938 ** We have a match.
1939 */
1940 t = newt;
1941 goto label;
1942 }
1943 }
1944 return WRONG;
1945 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001946label:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001947 newt = t + saved_seconds;
1948 if ((newt < t) != (saved_seconds < 0))
1949 return WRONG;
1950 t = newt;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001951 if ((*funcp)(&t, offset, tmp, sp)) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001952 *okayp = TRUE;
1953 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001954}
1955
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001956// BEGIN android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001957static time_t
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001958time2(tmp, funcp, offset, okayp, sp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001959struct tm * const tmp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001960struct tm * (* const funcp) P((const time_t*, long, struct tm*, const struct state*));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001961const long offset;
1962int * const okayp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001963const struct state * sp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001964{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001965 time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001966
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001967 /*
1968 ** First try without normalization of seconds
1969 ** (in case tm_sec contains a value associated with a leap second).
1970 ** If that fails, try with normalization of seconds.
1971 */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001972 t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
1973 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001974}
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001975// END android-changed
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001976
1977static time_t
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001978time1(tmp, funcp, offset, sp) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001979struct tm * const tmp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001980struct tm * (* const funcp) P((const time_t *, long, struct tm *, const struct state *));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001981const long offset;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001982const struct state * sp; // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001983{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001984 register time_t t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001985 register int samei, otheri;
1986 register int sameind, otherind;
1987 register int i;
1988 register int nseen;
1989 int seen[TZ_MAX_TYPES];
1990 int types[TZ_MAX_TYPES];
1991 int okay;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001992
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001993 if (tmp->tm_isdst > 1)
1994 tmp->tm_isdst = 1;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001995 t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001996#ifdef PCTS
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001997 /*
1998 ** PCTS code courtesy Grant Sullivan.
1999 */
2000 if (okay)
2001 return t;
2002 if (tmp->tm_isdst < 0)
2003 tmp->tm_isdst = 0; /* reset to std and try again */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002004#endif /* defined PCTS */
2005#ifndef PCTS
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002006 if (okay || tmp->tm_isdst < 0)
2007 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002008#endif /* !defined PCTS */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002009 /*
2010 ** We're supposed to assume that somebody took a time of one type
2011 ** and did some math on it that yielded a "struct tm" that's bad.
2012 ** We try to divine the type they started from and adjust to the
2013 ** type they need.
2014 */
2015 /*
2016 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
2017 */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002018 // BEGIN android-changed: support user-supplied sp.
2019 if (sp == NULL) {
2020 sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
2021 lclptr : gmtptr);
2022 }
2023 // BEGIN android-changed
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002024#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002025 if (sp == NULL)
2026 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002027#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002028 for (i = 0; i < sp->typecnt; ++i)
2029 seen[i] = FALSE;
2030 nseen = 0;
2031 for (i = sp->timecnt - 1; i >= 0; --i)
2032 if (!seen[sp->types[i]]) {
2033 seen[sp->types[i]] = TRUE;
2034 types[nseen++] = sp->types[i];
2035 }
2036 for (sameind = 0; sameind < nseen; ++sameind) {
2037 samei = types[sameind];
2038 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2039 continue;
2040 for (otherind = 0; otherind < nseen; ++otherind) {
2041 otheri = types[otherind];
2042 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2043 continue;
2044 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
2045 sp->ttis[samei].tt_gmtoff;
2046 tmp->tm_isdst = !tmp->tm_isdst;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002047 t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002048 if (okay)
2049 return t;
2050 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
2051 sp->ttis[samei].tt_gmtoff;
2052 tmp->tm_isdst = !tmp->tm_isdst;
2053 }
2054 }
2055 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002056}
2057
2058time_t
2059mktime(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002060struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002061{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002062 time_t result;
2063 _tzLock();
2064 tzset_locked();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002065 result = time1(tmp, localsub, 0L, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002066 _tzUnlock();
2067 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002068}
2069
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002070// BEGIN android-added
2071time_t
2072mktime_tz(tmp, tz)
2073struct tm * const tmp;
2074char const * tz;
2075{
2076 struct state st;
2077 if (tzload(tz, &st, TRUE) != 0) {
2078 // TODO: not sure what's best here, but for now, we fall back to gmt.
2079 gmtload(&st);
2080 }
2081 return time1(tmp, localsub, 0L, &st);
2082}
2083
2084void
2085localtime_tz(timep, tmp, tz)
2086const time_t * const timep;
2087struct tm * tmp;
2088const char* tz;
2089{
2090 struct state st;
2091 if (tzload(tz, &st, TRUE) != 0) {
2092 // TODO: not sure what's best here, but for now, we fall back to gmt.
2093 gmtload(&st);
2094 }
2095 localsub(timep, 0L, tmp, &st);
2096}
2097// END android-added
2098
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002099#ifdef STD_INSPIRED
2100
2101time_t
2102timelocal(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002103struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002104{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002105 tmp->tm_isdst = -1; /* in case it wasn't initialized */
2106 return mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002107}
2108
2109time_t
2110timegm(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002111struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002112{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002113 time_t result;
2114
2115 tmp->tm_isdst = 0;
2116 _tzLock();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002117 result = time1(tmp, gmtsub, 0L, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002118 _tzUnlock();
2119
2120 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002121}
2122
David 'Digit' Turner6481b912010-12-06 12:23:16 +01002123#if 0 /* disable due to lack of clear documentation on this function */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002124time_t
2125timeoff(tmp, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002126struct tm * const tmp;
2127const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002128{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002129 time_t result;
2130
2131 tmp->tm_isdst = 0;
2132 _tzLock();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002133 result = time1(tmp, gmtsub, offset, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002134 _tzUnlock();
2135
2136 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002137}
David 'Digit' Turner6481b912010-12-06 12:23:16 +01002138#endif /* 0 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002139
2140#endif /* defined STD_INSPIRED */
2141
2142#ifdef CMUCS
2143
2144/*
2145** The following is supplied for compatibility with
2146** previous versions of the CMUCS runtime library.
2147*/
2148
2149long
2150gtime(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002151struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002152{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002153 const time_t t = mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002154
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002155 if (t == WRONG)
2156 return -1;
2157 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002158}
2159
2160#endif /* defined CMUCS */
2161
2162/*
2163** XXX--is the below the right way to conditionalize??
2164*/
2165
2166#ifdef STD_INSPIRED
2167
2168/*
2169** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2170** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2171** is not the case if we are accounting for leap seconds.
2172** So, we provide the following conversion routines for use
2173** when exchanging timestamps with POSIX conforming systems.
2174*/
2175
2176static long
2177leapcorr(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002178time_t * timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002179{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002180 register struct state * sp;
2181 register struct lsinfo * lp;
2182 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002183
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002184 sp = lclptr;
2185 i = sp->leapcnt;
2186 while (--i >= 0) {
2187 lp = &sp->lsis[i];
2188 if (*timep >= lp->ls_trans)
2189 return lp->ls_corr;
2190 }
2191 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002192}
2193
2194time_t
2195time2posix(t)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002196time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002197{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002198 tzset();
2199 return t - leapcorr(&t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002200}
2201
2202time_t
2203posix2time(t)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002204time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002205{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002206 time_t x;
2207 time_t y;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002208
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002209 tzset();
2210 /*
2211 ** For a positive leap second hit, the result
2212 ** is not unique. For a negative leap second
2213 ** hit, the corresponding time doesn't exist,
2214 ** so we return an adjacent second.
2215 */
2216 x = t + leapcorr(&t);
2217 y = x - leapcorr(&x);
2218 if (y < t) {
2219 do {
2220 x++;
2221 y = x - leapcorr(&x);
2222 } while (y < t);
2223 if (t != y)
2224 return x - 1;
2225 } else if (y > t) {
2226 do {
2227 --x;
2228 y = x - leapcorr(&x);
2229 } while (y > t);
2230 if (t != y)
2231 return x + 1;
2232 }
2233 return x;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002234}
2235
2236#endif /* defined STD_INSPIRED */
Elliott Hughesd23af232012-10-17 16:30:47 -07002237
Elliott Hughes1c295722012-10-19 18:13:15 -07002238#include <assert.h>
Elliott Hughesd23af232012-10-17 16:30:47 -07002239#include <stdint.h>
Elliott Hughes8b954042012-10-18 13:42:59 -07002240#include <arpa/inet.h> // For ntohl(3).
Elliott Hughesd23af232012-10-17 16:30:47 -07002241
Elliott Hughes1c295722012-10-19 18:13:15 -07002242static int __bionic_open_tzdata_path(const char* path, const char* olson_id, int* data_size) {
2243 int fd = TEMP_FAILURE_RETRY(open(path, OPEN_MODE));
Elliott Hughesd23af232012-10-17 16:30:47 -07002244 if (fd == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002245 XLOG(("%s: could not open \"%s\": %s\n", __FUNCTION__, path, strerror(errno)));
2246 return -2; // Distinguish failure to find any data from failure to find a specific id.
Elliott Hughesd23af232012-10-17 16:30:47 -07002247 }
2248
2249 // byte[12] tzdata_version -- "tzdata2012f\0"
Elliott Hughesd23af232012-10-17 16:30:47 -07002250 // int index_offset
2251 // int data_offset
2252 // int zonetab_offset
2253 struct bionic_tzdata_header {
2254 char tzdata_version[12];
Elliott Hughesd23af232012-10-17 16:30:47 -07002255 int32_t index_offset;
2256 int32_t data_offset;
2257 int32_t zonetab_offset;
2258 } header;
2259 if (TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header))) != sizeof(header)) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002260 fprintf(stderr, "%s: could not read header: %s\n", __FUNCTION__, strerror(errno));
Elliott Hughesd23af232012-10-17 16:30:47 -07002261 close(fd);
2262 return -1;
2263 }
2264
2265 if (strncmp(header.tzdata_version, "tzdata", 6) != 0 || header.tzdata_version[11] != 0) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002266 fprintf(stderr, "%s: bad magic: %s\n", __FUNCTION__, header.tzdata_version);
Elliott Hughesd23af232012-10-17 16:30:47 -07002267 close(fd);
2268 return -1;
2269 }
Elliott Hughesd23af232012-10-17 16:30:47 -07002270
2271#if 0
Elliott Hughes23935352012-10-22 14:47:58 -07002272 fprintf(stderr, "version: %s\n", header.tzdata_version);
Elliott Hughesd23af232012-10-17 16:30:47 -07002273 fprintf(stderr, "index_offset = %d\n", ntohl(header.index_offset));
2274 fprintf(stderr, "data_offset = %d\n", ntohl(header.data_offset));
2275 fprintf(stderr, "zonetab_offset = %d\n", ntohl(header.zonetab_offset));
2276#endif
2277
2278 if (TEMP_FAILURE_RETRY(lseek(fd, ntohl(header.index_offset), SEEK_SET)) == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002279 fprintf(stderr, "%s: couldn't seek to index: %s\n", __FUNCTION__, strerror(errno));
Elliott Hughesd23af232012-10-17 16:30:47 -07002280 close(fd);
2281 return -1;
2282 }
2283
2284 off_t specific_zone_offset = -1;
2285
Elliott Hughes1c295722012-10-19 18:13:15 -07002286 static const size_t NAME_LENGTH = 40;
2287 unsigned char buf[NAME_LENGTH + 3 * sizeof(int32_t)];
2288 while (TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf))) == (ssize_t) sizeof(buf)) {
2289 char this_id[NAME_LENGTH + 1];
2290 memcpy(this_id, buf, NAME_LENGTH);
2291 this_id[NAME_LENGTH] = '\0';
Elliott Hughesd23af232012-10-17 16:30:47 -07002292
2293 if (strcmp(this_id, olson_id) == 0) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002294 specific_zone_offset = toint(buf + NAME_LENGTH) + ntohl(header.data_offset);
2295 *data_size = toint(buf + NAME_LENGTH + sizeof(int32_t));
Elliott Hughesd23af232012-10-17 16:30:47 -07002296 break;
2297 }
2298 }
2299
2300 if (specific_zone_offset == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002301 XLOG(("%s: couldn't find zone \"%s\"\n", __FUNCTION__, olson_id));
Elliott Hughesd23af232012-10-17 16:30:47 -07002302 close(fd);
2303 return -1;
2304 }
2305
2306 if (TEMP_FAILURE_RETRY(lseek(fd, specific_zone_offset, SEEK_SET)) == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002307 fprintf(stderr, "%s: could not seek to %ld: %s\n", __FUNCTION__, specific_zone_offset, strerror(errno));
Elliott Hughesd23af232012-10-17 16:30:47 -07002308 close(fd);
2309 return -1;
2310 }
2311
2312 return fd;
2313}
Elliott Hughes1c295722012-10-19 18:13:15 -07002314
2315static int __bionic_open_tzdata(const char* olson_id, int* data_size) {
2316 // TODO: use $ANDROID_DATA and $ANDROID_ROOT like libcore, to support bionic on the host.
2317 int fd = __bionic_open_tzdata_path("/data/misc/zoneinfo/tzdata", olson_id, data_size);
2318 if (fd < 0) {
2319 fd = __bionic_open_tzdata_path("/system/usr/share/zoneinfo/tzdata", olson_id, data_size);
2320 if (fd == -2) {
Elliott Hughes49271d82012-10-25 14:38:51 -07002321 // The first thing that 'recovery' does is try to format the current time. It doesn't have
2322 // any tzdata available, so we must not abort here --- doing so breaks the recovery image!
2323 fprintf(stderr, "%s: couldn't find any tzdata when looking for %s!\n", __FUNCTION__, olson_id);
Elliott Hughes1c295722012-10-19 18:13:15 -07002324 }
2325 }
2326 return fd;
2327}