blob: 8a54e81cc53feb2af1e94638c0f4518e0f05437a [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
Elliott Hughes4a05bef2013-03-11 17:17:02 -0700407tzload(const char* name, struct state* const sp, const int doextend)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800408{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700409 register const char * p;
410 register int i;
411 register int fid;
412 register int stored;
413 register int nread;
414 union {
415 struct tzhead tzhead;
416 char buf[2 * sizeof(struct tzhead) +
417 2 * sizeof *sp +
418 4 * TZ_MAX_TIMES];
419 } u;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800420 int toread = sizeof u.buf;
421
422 if (name == NULL && (name = TZDEFAULT) == NULL) {
423 XLOG(("tzload: null 'name' parameter\n" ));
424 return -1;
425 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700426 {
427 register int doaccess;
428 /*
429 ** Section 4.9.1 of the C standard says that
430 ** "FILENAME_MAX expands to an integral constant expression
431 ** that is the size needed for an array of char large enough
432 ** to hold the longest file name string that the implementation
433 ** guarantees can be opened."
434 */
435 char fullname[FILENAME_MAX + 1];
436 char *origname = (char*) name;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800437
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700438 if (name[0] == ':')
439 ++name;
440 doaccess = name[0] == '/';
441 if (!doaccess) {
442 if ((p = TZDIR) == NULL) {
443 XLOG(("tzload: null TZDIR macro ?\n" ));
444 return -1;
445 }
446 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) {
447 XLOG(( "tzload: path too long: %s/%s\n", p, name ));
448 return -1;
449 }
450 (void) strcpy(fullname, p);
451 (void) strcat(fullname, "/");
452 (void) strcat(fullname, name);
453 /*
454 ** Set doaccess if '.' (as in "../") shows up in name.
455 */
456 if (strchr(name, '.') != NULL)
457 doaccess = TRUE;
458 name = fullname;
459 }
460 if (doaccess && access(name, R_OK) != 0) {
461 XLOG(( "tzload: could not find '%s'\n", name ));
462 return -1;
463 }
464 if ((fid = open(name, OPEN_MODE)) == -1) {
Elliott Hughesd23af232012-10-17 16:30:47 -0700465 fid = __bionic_open_tzdata(origname, &toread);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800466 if (fid < 0) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800467 return -1;
468 }
469 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700470 }
471 nread = read(fid, u.buf, toread);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800472 if (close(fid) < 0 || nread <= 0) {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700473 XLOG(( "tzload: could not read content of '%s'\n", DATAFILE ));
474 return -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800475 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700476 for (stored = 4; stored <= 8; stored *= 2) {
477 int ttisstdcnt;
478 int ttisgmtcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800479
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700480 ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
481 ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
482 sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
483 sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
484 sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
485 sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
486 p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
487 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
488 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
489 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
490 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
491 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
492 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
493 return -1;
494 if (nread - (p - u.buf) <
495 sp->timecnt * stored + /* ats */
496 sp->timecnt + /* types */
497 sp->typecnt * 6 + /* ttinfos */
498 sp->charcnt + /* chars */
499 sp->leapcnt * (stored + 4) + /* lsinfos */
500 ttisstdcnt + /* ttisstds */
501 ttisgmtcnt) /* ttisgmts */
502 return -1;
503 for (i = 0; i < sp->timecnt; ++i) {
504 sp->ats[i] = (stored == 4) ?
505 detzcode(p) : detzcode64(p);
506 p += stored;
507 }
508 for (i = 0; i < sp->timecnt; ++i) {
509 sp->types[i] = (unsigned char) *p++;
510 if (sp->types[i] >= sp->typecnt)
511 return -1;
512 }
513 for (i = 0; i < sp->typecnt; ++i) {
514 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800515
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700516 ttisp = &sp->ttis[i];
517 ttisp->tt_gmtoff = detzcode(p);
518 p += 4;
519 ttisp->tt_isdst = (unsigned char) *p++;
520 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
521 return -1;
522 ttisp->tt_abbrind = (unsigned char) *p++;
523 if (ttisp->tt_abbrind < 0 ||
524 ttisp->tt_abbrind > sp->charcnt)
525 return -1;
526 }
527 for (i = 0; i < sp->charcnt; ++i)
528 sp->chars[i] = *p++;
529 sp->chars[i] = '\0'; /* ensure '\0' at end */
530 for (i = 0; i < sp->leapcnt; ++i) {
531 register struct lsinfo * lsisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800532
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700533 lsisp = &sp->lsis[i];
534 lsisp->ls_trans = (stored == 4) ?
535 detzcode(p) : detzcode64(p);
536 p += stored;
537 lsisp->ls_corr = detzcode(p);
538 p += 4;
539 }
540 for (i = 0; i < sp->typecnt; ++i) {
541 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800542
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700543 ttisp = &sp->ttis[i];
544 if (ttisstdcnt == 0)
545 ttisp->tt_ttisstd = FALSE;
546 else {
547 ttisp->tt_ttisstd = *p++;
548 if (ttisp->tt_ttisstd != TRUE &&
549 ttisp->tt_ttisstd != FALSE)
550 return -1;
551 }
552 }
553 for (i = 0; i < sp->typecnt; ++i) {
554 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800555
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700556 ttisp = &sp->ttis[i];
557 if (ttisgmtcnt == 0)
558 ttisp->tt_ttisgmt = FALSE;
559 else {
560 ttisp->tt_ttisgmt = *p++;
561 if (ttisp->tt_ttisgmt != TRUE &&
562 ttisp->tt_ttisgmt != FALSE)
563 return -1;
564 }
565 }
566 /*
567 ** Out-of-sort ats should mean we're running on a
568 ** signed time_t system but using a data file with
569 ** unsigned values (or vice versa).
570 */
571 for (i = 0; i < sp->timecnt - 2; ++i)
572 if (sp->ats[i] > sp->ats[i + 1]) {
573 ++i;
574 if (TYPE_SIGNED(time_t)) {
575 /*
576 ** Ignore the end (easy).
577 */
578 sp->timecnt = i;
579 } else {
580 /*
581 ** Ignore the beginning (harder).
582 */
583 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800584
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700585 for (j = 0; j + i < sp->timecnt; ++j) {
586 sp->ats[j] = sp->ats[j + i];
587 sp->types[j] = sp->types[j + i];
588 }
589 sp->timecnt = j;
590 }
591 break;
592 }
593 /*
594 ** If this is an old file, we're done.
595 */
596 if (u.tzhead.tzh_version[0] == '\0')
597 break;
598 nread -= p - u.buf;
599 for (i = 0; i < nread; ++i)
600 u.buf[i] = p[i];
601 /*
602 ** If this is a narrow integer time_t system, we're done.
603 */
604 if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
605 break;
606 }
607 if (doextend && nread > 2 &&
608 u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
609 sp->typecnt + 2 <= TZ_MAX_TYPES) {
610 struct state ts;
611 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800612
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700613 u.buf[nread - 1] = '\0';
614 result = tzparse(&u.buf[1], &ts, FALSE);
615 if (result == 0 && ts.typecnt == 2 &&
616 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
617 for (i = 0; i < 2; ++i)
618 ts.ttis[i].tt_abbrind +=
619 sp->charcnt;
620 for (i = 0; i < ts.charcnt; ++i)
621 sp->chars[sp->charcnt++] =
622 ts.chars[i];
623 i = 0;
624 while (i < ts.timecnt &&
625 ts.ats[i] <=
626 sp->ats[sp->timecnt - 1])
627 ++i;
628 while (i < ts.timecnt &&
629 sp->timecnt < TZ_MAX_TIMES) {
630 sp->ats[sp->timecnt] =
631 ts.ats[i];
632 sp->types[sp->timecnt] =
633 sp->typecnt +
634 ts.types[i];
635 ++sp->timecnt;
636 ++i;
637 }
638 sp->ttis[sp->typecnt++] = ts.ttis[0];
639 sp->ttis[sp->typecnt++] = ts.ttis[1];
640 }
641 }
642 i = 2 * YEARSPERREPEAT;
643 sp->goback = sp->goahead = sp->timecnt > i;
644 sp->goback &= sp->types[i] == sp->types[0] &&
645 differ_by_repeat(sp->ats[i], sp->ats[0]);
646 sp->goahead &=
647 sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
648 differ_by_repeat(sp->ats[sp->timecnt - 1],
649 sp->ats[sp->timecnt - 1 - i]);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800650 XLOG(( "tzload: load ok !!\n" ));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700651 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800652}
653
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700654static const int mon_lengths[2][MONSPERYEAR] = {
655 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
656 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800657};
658
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700659static const int year_lengths[2] = {
660 DAYSPERNYEAR, DAYSPERLYEAR
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800661};
662
663/*
664** Given a pointer into a time zone string, scan until a character that is not
665** a valid character in a zone name is found. Return a pointer to that
666** character.
667*/
668
669static const char *
670getzname(strp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700671register const char * strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800672{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700673 register char c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800674
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700675 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
676 c != '+')
677 ++strp;
678 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800679}
680
681/*
682** Given a pointer into an extended time zone string, scan until the ending
683** delimiter of the zone name is located. Return a pointer to the delimiter.
684**
685** As with getzname above, the legal character set is actually quite
686** restricted, with other characters producing undefined results.
687** We don't do any checking here; checking is done later in common-case code.
688*/
689
690static const char *
691getqzname(register const char *strp, const int delim)
692{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700693 register int c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800694
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700695 while ((c = *strp) != '\0' && c != delim)
696 ++strp;
697 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800698}
699
700/*
701** Given a pointer into a time zone string, extract a number from that string.
702** Check that the number is within a specified range; if it is not, return
703** NULL.
704** Otherwise, return a pointer to the first character not part of the number.
705*/
706
707static const char *
708getnum(strp, nump, min, max)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700709register const char * strp;
710int * const nump;
711const int min;
712const int max;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800713{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700714 register char c;
715 register int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800716
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700717 if (strp == NULL || !is_digit(c = *strp))
718 return NULL;
719 num = 0;
720 do {
721 num = num * 10 + (c - '0');
722 if (num > max)
723 return NULL; /* illegal value */
724 c = *++strp;
725 } while (is_digit(c));
726 if (num < min)
727 return NULL; /* illegal value */
728 *nump = num;
729 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800730}
731
732/*
733** Given a pointer into a time zone string, extract a number of seconds,
734** in hh[:mm[:ss]] form, from the string.
735** If any error occurs, return NULL.
736** Otherwise, return a pointer to the first character not part of the number
737** of seconds.
738*/
739
740static const char *
741getsecs(strp, secsp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700742register const char * strp;
743long * const secsp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800744{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700745 int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800746
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700747 /*
748 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
749 ** "M10.4.6/26", which does not conform to Posix,
750 ** but which specifies the equivalent of
751 ** ``02:00 on the first Sunday on or after 23 Oct''.
752 */
753 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
754 if (strp == NULL)
755 return NULL;
756 *secsp = num * (long) SECSPERHOUR;
757 if (*strp == ':') {
758 ++strp;
759 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
760 if (strp == NULL)
761 return NULL;
762 *secsp += num * SECSPERMIN;
763 if (*strp == ':') {
764 ++strp;
765 /* `SECSPERMIN' allows for leap seconds. */
766 strp = getnum(strp, &num, 0, SECSPERMIN);
767 if (strp == NULL)
768 return NULL;
769 *secsp += num;
770 }
771 }
772 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800773}
774
775/*
776** Given a pointer into a time zone string, extract an offset, in
777** [+-]hh[:mm[:ss]] form, from the string.
778** If any error occurs, return NULL.
779** Otherwise, return a pointer to the first character not part of the time.
780*/
781
782static const char *
783getoffset(strp, offsetp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700784register const char * strp;
785long * const offsetp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800786{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700787 register int neg = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800788
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700789 if (*strp == '-') {
790 neg = 1;
791 ++strp;
792 } else if (*strp == '+')
793 ++strp;
794 strp = getsecs(strp, offsetp);
795 if (strp == NULL)
796 return NULL; /* illegal time */
797 if (neg)
798 *offsetp = -*offsetp;
799 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800800}
801
802/*
803** Given a pointer into a time zone string, extract a rule in the form
804** date[/time]. See POSIX section 8 for the format of "date" and "time".
805** If a valid rule is not found, return NULL.
806** Otherwise, return a pointer to the first character not part of the rule.
807*/
808
809static const char *
810getrule(strp, rulep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700811const char * strp;
812register struct rule * const rulep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800813{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700814 if (*strp == 'J') {
815 /*
816 ** Julian day.
817 */
818 rulep->r_type = JULIAN_DAY;
819 ++strp;
820 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
821 } else if (*strp == 'M') {
822 /*
823 ** Month, week, day.
824 */
825 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
826 ++strp;
827 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
828 if (strp == NULL)
829 return NULL;
830 if (*strp++ != '.')
831 return NULL;
832 strp = getnum(strp, &rulep->r_week, 1, 5);
833 if (strp == NULL)
834 return NULL;
835 if (*strp++ != '.')
836 return NULL;
837 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
838 } else if (is_digit(*strp)) {
839 /*
840 ** Day of year.
841 */
842 rulep->r_type = DAY_OF_YEAR;
843 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
844 } else return NULL; /* invalid format */
845 if (strp == NULL)
846 return NULL;
847 if (*strp == '/') {
848 /*
849 ** Time specified.
850 */
851 ++strp;
852 strp = getsecs(strp, &rulep->r_time);
853 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
854 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800855}
856
857/*
858** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
859** year, a rule, and the offset from UTC at the time that rule takes effect,
860** calculate the Epoch-relative time that rule takes effect.
861*/
862
863static time_t
864transtime(janfirst, year, rulep, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700865const time_t janfirst;
866const int year;
867register const struct rule * const rulep;
868const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800869{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700870 register int leapyear;
871 register time_t value;
872 register int i;
873 int d, m1, yy0, yy1, yy2, dow;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800874
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700875 INITIALIZE(value);
876 leapyear = isleap(year);
877 switch (rulep->r_type) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800878
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700879 case JULIAN_DAY:
880 /*
881 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
882 ** years.
883 ** In non-leap years, or if the day number is 59 or less, just
884 ** add SECSPERDAY times the day number-1 to the time of
885 ** January 1, midnight, to get the day.
886 */
887 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
888 if (leapyear && rulep->r_day >= 60)
889 value += SECSPERDAY;
890 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800891
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700892 case DAY_OF_YEAR:
893 /*
894 ** n - day of year.
895 ** Just add SECSPERDAY times the day number to the time of
896 ** January 1, midnight, to get the day.
897 */
898 value = janfirst + rulep->r_day * SECSPERDAY;
899 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800900
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700901 case MONTH_NTH_DAY_OF_WEEK:
902 /*
903 ** Mm.n.d - nth "dth day" of month m.
904 */
905 value = janfirst;
906 for (i = 0; i < rulep->r_mon - 1; ++i)
907 value += mon_lengths[leapyear][i] * SECSPERDAY;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800908
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700909 /*
910 ** Use Zeller's Congruence to get day-of-week of first day of
911 ** month.
912 */
913 m1 = (rulep->r_mon + 9) % 12 + 1;
914 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
915 yy1 = yy0 / 100;
916 yy2 = yy0 % 100;
917 dow = ((26 * m1 - 2) / 10 +
918 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
919 if (dow < 0)
920 dow += DAYSPERWEEK;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800921
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700922 /*
923 ** "dow" is the day-of-week of the first day of the month. Get
924 ** the day-of-month (zero-origin) of the first "dow" day of the
925 ** month.
926 */
927 d = rulep->r_day - dow;
928 if (d < 0)
929 d += DAYSPERWEEK;
930 for (i = 1; i < rulep->r_week; ++i) {
931 if (d + DAYSPERWEEK >=
932 mon_lengths[leapyear][rulep->r_mon - 1])
933 break;
934 d += DAYSPERWEEK;
935 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800936
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700937 /*
938 ** "d" is the day-of-month (zero-origin) of the day we want.
939 */
940 value += d * SECSPERDAY;
941 break;
942 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800943
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700944 /*
945 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
946 ** question. To get the Epoch-relative time of the specified local
947 ** time on that day, add the transition time and the current offset
948 ** from UTC.
949 */
950 return value + rulep->r_time + offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800951}
952
953/*
954** Given a POSIX section 8-style TZ string, fill in the rule tables as
955** appropriate.
956*/
957
958static int
959tzparse(name, sp, lastditch)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700960const char * name;
961register struct state * const sp;
962const int lastditch;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800963{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700964 const char * stdname;
965 const char * dstname;
966 size_t stdlen;
967 size_t dstlen;
968 long stdoffset;
969 long dstoffset;
970 register time_t * atp;
971 register unsigned char * typep;
972 register char * cp;
973 register int load_result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800974
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700975 INITIALIZE(dstname);
976 stdname = name;
977 if (lastditch) {
978 stdlen = strlen(name); /* length of standard zone name */
979 name += stdlen;
980 if (stdlen >= sizeof sp->chars)
981 stdlen = (sizeof sp->chars) - 1;
982 stdoffset = 0;
983 } else {
984 if (*name == '<') {
985 name++;
986 stdname = name;
987 name = getqzname(name, '>');
988 if (*name != '>')
989 return (-1);
990 stdlen = name - stdname;
991 name++;
992 } else {
993 name = getzname(name);
994 stdlen = name - stdname;
995 }
996 if (*name == '\0')
997 return -1;
998 name = getoffset(name, &stdoffset);
999 if (name == NULL)
1000 return -1;
1001 }
1002 load_result = tzload(TZDEFRULES, sp, FALSE);
1003 if (load_result != 0)
1004 sp->leapcnt = 0; /* so, we're off a little */
1005 sp->timecnt = 0;
1006 if (*name != '\0') {
1007 if (*name == '<') {
1008 dstname = ++name;
1009 name = getqzname(name, '>');
1010 if (*name != '>')
1011 return -1;
1012 dstlen = name - dstname;
1013 name++;
1014 } else {
1015 dstname = name;
1016 name = getzname(name);
1017 dstlen = name - dstname; /* length of DST zone name */
1018 }
1019 if (*name != '\0' && *name != ',' && *name != ';') {
1020 name = getoffset(name, &dstoffset);
1021 if (name == NULL)
1022 return -1;
1023 } else dstoffset = stdoffset - SECSPERHOUR;
1024 if (*name == '\0' && load_result != 0)
1025 name = TZDEFRULESTRING;
1026 if (*name == ',' || *name == ';') {
1027 struct rule start;
1028 struct rule end;
1029 register int year;
1030 register time_t janfirst;
1031 time_t starttime;
1032 time_t endtime;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001033
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001034 ++name;
1035 if ((name = getrule(name, &start)) == NULL)
1036 return -1;
1037 if (*name++ != ',')
1038 return -1;
1039 if ((name = getrule(name, &end)) == NULL)
1040 return -1;
1041 if (*name != '\0')
1042 return -1;
1043 sp->typecnt = 2; /* standard time and DST */
1044 /*
1045 ** Two transitions per year, from EPOCH_YEAR forward.
1046 */
1047 sp->ttis[0].tt_gmtoff = -dstoffset;
1048 sp->ttis[0].tt_isdst = 1;
1049 sp->ttis[0].tt_abbrind = stdlen + 1;
1050 sp->ttis[1].tt_gmtoff = -stdoffset;
1051 sp->ttis[1].tt_isdst = 0;
1052 sp->ttis[1].tt_abbrind = 0;
1053 atp = sp->ats;
1054 typep = sp->types;
1055 janfirst = 0;
1056 for (year = EPOCH_YEAR;
1057 sp->timecnt + 2 <= TZ_MAX_TIMES;
1058 ++year) {
1059 time_t newfirst;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001060
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001061 starttime = transtime(janfirst, year, &start,
1062 stdoffset);
1063 endtime = transtime(janfirst, year, &end,
1064 dstoffset);
1065 if (starttime > endtime) {
1066 *atp++ = endtime;
1067 *typep++ = 1; /* DST ends */
1068 *atp++ = starttime;
1069 *typep++ = 0; /* DST begins */
1070 } else {
1071 *atp++ = starttime;
1072 *typep++ = 0; /* DST begins */
1073 *atp++ = endtime;
1074 *typep++ = 1; /* DST ends */
1075 }
1076 sp->timecnt += 2;
1077 newfirst = janfirst;
1078 newfirst += year_lengths[isleap(year)] *
1079 SECSPERDAY;
1080 if (newfirst <= janfirst)
1081 break;
1082 janfirst = newfirst;
1083 }
1084 } else {
1085 register long theirstdoffset;
1086 register long theirdstoffset;
1087 register long theiroffset;
1088 register int isdst;
1089 register int i;
1090 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001091
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001092 if (*name != '\0')
1093 return -1;
1094 /*
1095 ** Initial values of theirstdoffset and theirdstoffset.
1096 */
1097 theirstdoffset = 0;
1098 for (i = 0; i < sp->timecnt; ++i) {
1099 j = sp->types[i];
1100 if (!sp->ttis[j].tt_isdst) {
1101 theirstdoffset =
1102 -sp->ttis[j].tt_gmtoff;
1103 break;
1104 }
1105 }
1106 theirdstoffset = 0;
1107 for (i = 0; i < sp->timecnt; ++i) {
1108 j = sp->types[i];
1109 if (sp->ttis[j].tt_isdst) {
1110 theirdstoffset =
1111 -sp->ttis[j].tt_gmtoff;
1112 break;
1113 }
1114 }
1115 /*
1116 ** Initially we're assumed to be in standard time.
1117 */
1118 isdst = FALSE;
1119 theiroffset = theirstdoffset;
1120 /*
1121 ** Now juggle transition times and types
1122 ** tracking offsets as you do.
1123 */
1124 for (i = 0; i < sp->timecnt; ++i) {
1125 j = sp->types[i];
1126 sp->types[i] = sp->ttis[j].tt_isdst;
1127 if (sp->ttis[j].tt_ttisgmt) {
1128 /* No adjustment to transition time */
1129 } else {
1130 /*
1131 ** If summer time is in effect, and the
1132 ** transition time was not specified as
1133 ** standard time, add the summer time
1134 ** offset to the transition time;
1135 ** otherwise, add the standard time
1136 ** offset to the transition time.
1137 */
1138 /*
1139 ** Transitions from DST to DDST
1140 ** will effectively disappear since
1141 ** POSIX provides for only one DST
1142 ** offset.
1143 */
1144 if (isdst && !sp->ttis[j].tt_ttisstd) {
1145 sp->ats[i] += dstoffset -
1146 theirdstoffset;
1147 } else {
1148 sp->ats[i] += stdoffset -
1149 theirstdoffset;
1150 }
1151 }
1152 theiroffset = -sp->ttis[j].tt_gmtoff;
1153 if (sp->ttis[j].tt_isdst)
1154 theirdstoffset = theiroffset;
1155 else theirstdoffset = theiroffset;
1156 }
1157 /*
1158 ** Finally, fill in ttis.
1159 ** ttisstd and ttisgmt need not be handled.
1160 */
1161 sp->ttis[0].tt_gmtoff = -stdoffset;
1162 sp->ttis[0].tt_isdst = FALSE;
1163 sp->ttis[0].tt_abbrind = 0;
1164 sp->ttis[1].tt_gmtoff = -dstoffset;
1165 sp->ttis[1].tt_isdst = TRUE;
1166 sp->ttis[1].tt_abbrind = stdlen + 1;
1167 sp->typecnt = 2;
1168 }
1169 } else {
1170 dstlen = 0;
1171 sp->typecnt = 1; /* only standard time */
1172 sp->timecnt = 0;
1173 sp->ttis[0].tt_gmtoff = -stdoffset;
1174 sp->ttis[0].tt_isdst = 0;
1175 sp->ttis[0].tt_abbrind = 0;
1176 }
1177 sp->charcnt = stdlen + 1;
1178 if (dstlen != 0)
1179 sp->charcnt += dstlen + 1;
1180 if ((size_t) sp->charcnt > sizeof sp->chars)
1181 return -1;
1182 cp = sp->chars;
1183 (void) strncpy(cp, stdname, stdlen);
1184 cp += stdlen;
1185 *cp++ = '\0';
1186 if (dstlen != 0) {
1187 (void) strncpy(cp, dstname, dstlen);
1188 *(cp + dstlen) = '\0';
1189 }
1190 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001191}
1192
1193static void
1194gmtload(sp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001195struct state * const sp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001196{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001197 if (tzload(gmt, sp, TRUE) != 0)
1198 (void) tzparse(gmt, sp, TRUE);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001199}
1200
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001201static void
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001202tzsetwall P((void))
1203{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001204 if (lcl_is_set < 0)
1205 return;
1206 lcl_is_set = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001207
1208#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001209 if (lclptr == NULL) {
1210 lclptr = (struct state *) malloc(sizeof *lclptr);
1211 if (lclptr == NULL) {
1212 settzname(); /* all we can do */
1213 return;
1214 }
1215 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001216#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001217 if (tzload((char *) NULL, lclptr, TRUE) != 0)
1218 gmtload(lclptr);
1219 settzname();
1220}
1221
1222static void
1223tzset_locked P((void))
1224{
1225 register const char * name = NULL;
1226 static char buf[PROP_VALUE_MAX];
1227
1228 name = getenv("TZ");
1229
1230 // try the "persist.sys.timezone" system property first
1231 if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0)
1232 name = buf;
1233
1234 if (name == NULL) {
1235 tzsetwall();
1236 return;
1237 }
1238
1239 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
1240 return;
1241 lcl_is_set = strlen(name) < sizeof lcl_TZname;
1242 if (lcl_is_set)
1243 (void) strcpy(lcl_TZname, name);
1244
1245#ifdef ALL_STATE
1246 if (lclptr == NULL) {
1247 lclptr = (struct state *) malloc(sizeof *lclptr);
1248 if (lclptr == NULL) {
1249 settzname(); /* all we can do */
1250 return;
1251 }
1252 }
1253#endif /* defined ALL_STATE */
1254 if (*name == '\0') {
1255 /*
1256 ** User wants it fast rather than right.
1257 */
1258 lclptr->leapcnt = 0; /* so, we're off a little */
1259 lclptr->timecnt = 0;
1260 lclptr->typecnt = 0;
1261 lclptr->ttis[0].tt_isdst = 0;
1262 lclptr->ttis[0].tt_gmtoff = 0;
1263 lclptr->ttis[0].tt_abbrind = 0;
1264 (void) strcpy(lclptr->chars, gmt);
1265 } else if (tzload(name, lclptr, TRUE) != 0)
1266 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
1267 (void) gmtload(lclptr);
1268 settzname();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001269}
1270
1271void
1272tzset P((void))
1273{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001274 _tzLock();
1275 tzset_locked();
1276 _tzUnlock();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001277}
1278
1279/*
1280** The easy way to behave "as if no library function calls" localtime
1281** is to not call it--so we drop its guts into "localsub", which can be
1282** freely called. (And no, the PANS doesn't require the above behavior--
1283** but it *is* desirable.)
1284**
1285** The unused offset argument is for the benefit of mktime variants.
1286*/
1287
1288/*ARGSUSED*/
1289static struct tm *
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001290localsub(timep, offset, tmp, sp) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001291const time_t * const timep;
1292const long offset;
1293struct tm * const tmp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001294const struct state * sp; // android-added: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001295{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001296 register const struct ttinfo * ttisp;
1297 register int i;
1298 register struct tm * result;
1299 const time_t t = *timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001300
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001301 // BEGIN android-changed: support user-supplied sp.
1302 if (sp == NULL) {
1303 sp = lclptr;
1304 }
1305 // END android-changed
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001306#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001307 if (sp == NULL)
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001308 return gmtsub(timep, offset, tmp, sp); // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001309#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001310 if ((sp->goback && t < sp->ats[0]) ||
1311 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1312 time_t newt = t;
1313 register time_t seconds;
1314 register time_t tcycles;
1315 register int_fast64_t icycles;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001316
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001317 if (t < sp->ats[0])
1318 seconds = sp->ats[0] - t;
1319 else seconds = t - sp->ats[sp->timecnt - 1];
1320 --seconds;
1321 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1322 ++tcycles;
1323 icycles = tcycles;
1324 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1325 return NULL;
1326 seconds = icycles;
1327 seconds *= YEARSPERREPEAT;
1328 seconds *= AVGSECSPERYEAR;
1329 if (t < sp->ats[0])
1330 newt += seconds;
1331 else newt -= seconds;
1332 if (newt < sp->ats[0] ||
1333 newt > sp->ats[sp->timecnt - 1])
1334 return NULL; /* "cannot happen" */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001335 result = localsub(&newt, offset, tmp, sp); // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001336 if (result == tmp) {
1337 register time_t newy;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001338
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001339 newy = tmp->tm_year;
1340 if (t < sp->ats[0])
1341 newy -= icycles * YEARSPERREPEAT;
1342 else newy += icycles * YEARSPERREPEAT;
1343 tmp->tm_year = newy;
1344 if (tmp->tm_year != newy)
1345 return NULL;
1346 }
1347 return result;
1348 }
1349 if (sp->timecnt == 0 || t < sp->ats[0]) {
1350 i = 0;
1351 while (sp->ttis[i].tt_isdst)
1352 if (++i >= sp->typecnt) {
1353 i = 0;
1354 break;
1355 }
1356 } else {
1357 register int lo = 1;
1358 register int hi = sp->timecnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001359
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001360 while (lo < hi) {
1361 register int mid = (lo + hi) >> 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001362
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001363 if (t < sp->ats[mid])
1364 hi = mid;
1365 else lo = mid + 1;
1366 }
1367 i = (int) sp->types[lo - 1];
1368 }
1369 ttisp = &sp->ttis[i];
1370 /*
1371 ** To get (wrong) behavior that's compatible with System V Release 2.0
1372 ** you'd replace the statement below with
1373 ** t += ttisp->tt_gmtoff;
1374 ** timesub(&t, 0L, sp, tmp);
1375 */
1376 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1377 tmp->tm_isdst = ttisp->tt_isdst;
1378 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001379#ifdef TM_ZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001380 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001381#endif /* defined TM_ZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001382 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001383}
1384
1385struct tm *
1386localtime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001387const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001388{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001389 return localtime_r(timep, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001390}
1391
1392/*
1393** Re-entrant version of localtime.
1394*/
1395
1396struct tm *
1397localtime_r(timep, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001398const time_t * const timep;
1399struct tm * tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001400{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001401 struct tm* result;
1402
1403 _tzLock();
1404 tzset_locked();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001405 result = localsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001406 _tzUnlock();
1407
1408 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001409}
1410
1411/*
1412** gmtsub is to gmtime as localsub is to localtime.
1413*/
1414
1415static struct tm *
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001416gmtsub(timep, offset, tmp, sp) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001417const time_t * const timep;
1418const long offset;
1419struct tm * const tmp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001420const struct state * sp; // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001421{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001422 register struct tm * result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001423
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001424 (void) sp; // android-added: unused.
1425
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001426 if (!gmt_is_set) {
1427 gmt_is_set = TRUE;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001428#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001429 gmtptr = (struct state *) malloc(sizeof *gmtptr);
1430 if (gmtptr != NULL)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001431#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001432 gmtload(gmtptr);
1433 }
1434 result = timesub(timep, offset, gmtptr, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001435#ifdef TM_ZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001436 /*
1437 ** Could get fancy here and deliver something such as
1438 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
1439 ** but this is no time for a treasure hunt.
1440 */
1441 if (offset != 0)
1442 tmp->TM_ZONE = wildabbr;
1443 else {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001444#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001445 if (gmtptr == NULL)
1446 tmp->TM_ZONE = gmt;
1447 else tmp->TM_ZONE = gmtptr->chars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001448#endif /* defined ALL_STATE */
1449#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001450 tmp->TM_ZONE = gmtptr->chars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001451#endif /* State Farm */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001452 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001453#endif /* defined TM_ZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001454 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001455}
1456
1457struct tm *
1458gmtime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001459const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001460{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001461 return gmtime_r(timep, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001462}
1463
1464/*
1465* Re-entrant version of gmtime.
1466*/
1467
1468struct tm *
1469gmtime_r(timep, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001470const time_t * const timep;
1471struct tm * tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001472{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001473 struct tm* result;
1474
1475 _tzLock();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001476 result = gmtsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001477 _tzUnlock();
1478
1479 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001480}
1481
1482#ifdef STD_INSPIRED
David 'Digit' Turner6481b912010-12-06 12:23:16 +01001483#if 0 /* disabled because there is no good documentation for this function */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001484struct tm *
1485offtime(timep, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001486const time_t * const timep;
1487const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001488{
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001489 return gmtsub(timep, offset, &tmGlobal, NULL); // android-changed: extra parameter.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001490}
David 'Digit' Turner6481b912010-12-06 12:23:16 +01001491#endif /* 0 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001492#endif /* defined STD_INSPIRED */
1493
1494/*
1495** Return the number of leap years through the end of the given year
1496** where, to make the math easy, the answer for year zero is defined as zero.
1497*/
1498
1499static int
1500leaps_thru_end_of(y)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001501register const int y;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001502{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001503 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1504 -(leaps_thru_end_of(-(y + 1)) + 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001505}
1506
1507static struct tm *
1508timesub(timep, offset, sp, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001509const time_t * const timep;
1510const long offset;
1511register const struct state * const sp;
1512register struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001513{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001514 register const struct lsinfo * lp;
1515 register time_t tdays;
1516 register int idays; /* unsigned would be so 2003 */
1517 register long rem;
1518 int y;
1519 register const int * ip;
1520 register long corr;
1521 register int hit;
1522 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001523
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001524 corr = 0;
1525 hit = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001526#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001527 i = (sp == NULL) ? 0 : sp->leapcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001528#endif /* defined ALL_STATE */
1529#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001530 i = sp->leapcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001531#endif /* State Farm */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001532 while (--i >= 0) {
1533 lp = &sp->lsis[i];
1534 if (*timep >= lp->ls_trans) {
1535 if (*timep == lp->ls_trans) {
1536 hit = ((i == 0 && lp->ls_corr > 0) ||
1537 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1538 if (hit)
1539 while (i > 0 &&
1540 sp->lsis[i].ls_trans ==
1541 sp->lsis[i - 1].ls_trans + 1 &&
1542 sp->lsis[i].ls_corr ==
1543 sp->lsis[i - 1].ls_corr + 1) {
1544 ++hit;
1545 --i;
1546 }
1547 }
1548 corr = lp->ls_corr;
1549 break;
1550 }
1551 }
1552 y = EPOCH_YEAR;
1553 tdays = *timep / SECSPERDAY;
1554 rem = *timep - tdays * SECSPERDAY;
1555 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1556 int newy;
1557 register time_t tdelta;
1558 register int idelta;
1559 register int leapdays;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001560
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001561 tdelta = tdays / DAYSPERLYEAR;
1562 idelta = tdelta;
1563 if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
1564 return NULL;
1565 if (idelta == 0)
1566 idelta = (tdays < 0) ? -1 : 1;
1567 newy = y;
1568 if (increment_overflow(&newy, idelta))
1569 return NULL;
1570 leapdays = leaps_thru_end_of(newy - 1) -
1571 leaps_thru_end_of(y - 1);
1572 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1573 tdays -= leapdays;
1574 y = newy;
1575 }
1576 {
1577 register long seconds;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001578
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001579 seconds = tdays * SECSPERDAY + 0.5;
1580 tdays = seconds / SECSPERDAY;
1581 rem += seconds - tdays * SECSPERDAY;
1582 }
1583 /*
1584 ** Given the range, we can now fearlessly cast...
1585 */
1586 idays = tdays;
1587 rem += offset - corr;
1588 while (rem < 0) {
1589 rem += SECSPERDAY;
1590 --idays;
1591 }
1592 while (rem >= SECSPERDAY) {
1593 rem -= SECSPERDAY;
1594 ++idays;
1595 }
1596 while (idays < 0) {
1597 if (increment_overflow(&y, -1))
1598 return NULL;
1599 idays += year_lengths[isleap(y)];
1600 }
1601 while (idays >= year_lengths[isleap(y)]) {
1602 idays -= year_lengths[isleap(y)];
1603 if (increment_overflow(&y, 1))
1604 return NULL;
1605 }
1606 tmp->tm_year = y;
1607 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1608 return NULL;
1609 tmp->tm_yday = idays;
1610 /*
1611 ** The "extra" mods below avoid overflow problems.
1612 */
1613 tmp->tm_wday = EPOCH_WDAY +
1614 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
1615 (DAYSPERNYEAR % DAYSPERWEEK) +
1616 leaps_thru_end_of(y - 1) -
1617 leaps_thru_end_of(EPOCH_YEAR - 1) +
1618 idays;
1619 tmp->tm_wday %= DAYSPERWEEK;
1620 if (tmp->tm_wday < 0)
1621 tmp->tm_wday += DAYSPERWEEK;
1622 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1623 rem %= SECSPERHOUR;
1624 tmp->tm_min = (int) (rem / SECSPERMIN);
1625 /*
1626 ** A positive leap second requires a special
1627 ** representation. This uses "... ??:59:60" et seq.
1628 */
1629 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1630 ip = mon_lengths[isleap(y)];
1631 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1632 idays -= ip[tmp->tm_mon];
1633 tmp->tm_mday = (int) (idays + 1);
1634 tmp->tm_isdst = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001635#ifdef TM_GMTOFF
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001636 tmp->TM_GMTOFF = offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001637#endif /* defined TM_GMTOFF */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001638 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001639}
1640
1641char *
1642ctime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001643const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001644{
1645/*
1646** Section 4.12.3.2 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001647** The ctime function converts the calendar time pointed to by timer
1648** to local time in the form of a string. It is equivalent to
1649** asctime(localtime(timer))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001650*/
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001651 return asctime(localtime(timep));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001652}
1653
1654char *
1655ctime_r(timep, buf)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001656const time_t * const timep;
1657char * buf;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001658{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001659 struct tm mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001660
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001661 return asctime_r(localtime_r(timep, &mytm), buf);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001662}
1663
1664/*
1665** Adapted from code provided by Robert Elz, who writes:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001666** The "best" way to do mktime I think is based on an idea of Bob
1667** Kridle's (so its said...) from a long time ago.
1668** It does a binary search of the time_t space. Since time_t's are
1669** just 32 bits, its a max of 32 iterations (even at 64 bits it
1670** would still be very reasonable).
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001671*/
1672
1673#ifndef WRONG
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001674#define WRONG (-1)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001675#endif /* !defined WRONG */
1676
1677/*
1678** Simplified normalize logic courtesy Paul Eggert.
1679*/
1680
1681static int
1682increment_overflow(number, delta)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001683int * number;
1684int delta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001685{
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001686 unsigned number0 = (unsigned)*number;
1687 unsigned number1 = (unsigned)(number0 + delta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001688
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001689 *number = (int)number1;
1690
1691 if (delta >= 0) {
1692 return ((int)number1 < (int)number0);
1693 } else {
1694 return ((int)number1 > (int)number0);
1695 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001696}
1697
1698static int
1699long_increment_overflow(number, delta)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001700long * number;
1701int delta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001702{
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001703 unsigned long number0 = (unsigned long)*number;
1704 unsigned long number1 = (unsigned long)(number0 + delta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001705
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001706 *number = (long)number1;
1707
1708 if (delta >= 0) {
1709 return ((long)number1 < (long)number0);
1710 } else {
1711 return ((long)number1 > (long)number0);
1712 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001713}
1714
1715static int
1716normalize_overflow(tensptr, unitsptr, base)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001717int * const tensptr;
1718int * const unitsptr;
1719const int base;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001720{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001721 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001722
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001723 tensdelta = (*unitsptr >= 0) ?
1724 (*unitsptr / base) :
1725 (-1 - (-1 - *unitsptr) / base);
1726 *unitsptr -= tensdelta * base;
1727 return increment_overflow(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001728}
1729
1730static int
1731long_normalize_overflow(tensptr, unitsptr, base)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001732long * const tensptr;
1733int * const unitsptr;
1734const int base;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001735{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001736 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001737
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001738 tensdelta = (*unitsptr >= 0) ?
1739 (*unitsptr / base) :
1740 (-1 - (-1 - *unitsptr) / base);
1741 *unitsptr -= tensdelta * base;
1742 return long_increment_overflow(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001743}
1744
1745static int
1746tmcomp(atmp, btmp)
1747register const struct tm * const atmp;
1748register const struct tm * const btmp;
1749{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001750 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001751
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001752 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1753 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1754 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1755 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1756 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1757 result = atmp->tm_sec - btmp->tm_sec;
1758 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001759}
1760
1761static time_t
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001762time2sub(tmp, funcp, offset, okayp, do_norm_secs, sp) // android-changed: added sp
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001763struct tm * const tmp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001764struct 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 -07001765const long offset;
1766int * const okayp;
1767const int do_norm_secs;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001768const struct state * sp; // android-changed: added sp
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001769{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001770 register int dir;
1771 register int i, j;
1772 register int saved_seconds;
1773 register long li;
1774 register time_t lo;
1775 register time_t hi;
1776 long y;
1777 time_t newt;
1778 time_t t;
1779 struct tm yourtm, mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001780
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001781 *okayp = FALSE;
1782 yourtm = *tmp;
1783 if (do_norm_secs) {
1784 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1785 SECSPERMIN))
1786 return WRONG;
1787 }
1788 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1789 return WRONG;
1790 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1791 return WRONG;
1792 y = yourtm.tm_year;
1793 if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
1794 return WRONG;
1795 /*
1796 ** Turn y into an actual year number for now.
1797 ** It is converted back to an offset from TM_YEAR_BASE later.
1798 */
1799 if (long_increment_overflow(&y, TM_YEAR_BASE))
1800 return WRONG;
1801 while (yourtm.tm_mday <= 0) {
1802 if (long_increment_overflow(&y, -1))
1803 return WRONG;
1804 li = y + (1 < yourtm.tm_mon);
1805 yourtm.tm_mday += year_lengths[isleap(li)];
1806 }
1807 while (yourtm.tm_mday > DAYSPERLYEAR) {
1808 li = y + (1 < yourtm.tm_mon);
1809 yourtm.tm_mday -= year_lengths[isleap(li)];
1810 if (long_increment_overflow(&y, 1))
1811 return WRONG;
1812 }
1813 for ( ; ; ) {
1814 i = mon_lengths[isleap(y)][yourtm.tm_mon];
1815 if (yourtm.tm_mday <= i)
1816 break;
1817 yourtm.tm_mday -= i;
1818 if (++yourtm.tm_mon >= MONSPERYEAR) {
1819 yourtm.tm_mon = 0;
1820 if (long_increment_overflow(&y, 1))
1821 return WRONG;
1822 }
1823 }
1824 if (long_increment_overflow(&y, -TM_YEAR_BASE))
1825 return WRONG;
1826 yourtm.tm_year = y;
1827 if (yourtm.tm_year != y)
1828 return WRONG;
1829 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
1830 saved_seconds = 0;
1831 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
1832 /*
1833 ** We can't set tm_sec to 0, because that might push the
1834 ** time below the minimum representable time.
1835 ** Set tm_sec to 59 instead.
1836 ** This assumes that the minimum representable time is
1837 ** not in the same minute that a leap second was deleted from,
1838 ** which is a safer assumption than using 58 would be.
1839 */
1840 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1841 return WRONG;
1842 saved_seconds = yourtm.tm_sec;
1843 yourtm.tm_sec = SECSPERMIN - 1;
1844 } else {
1845 saved_seconds = yourtm.tm_sec;
1846 yourtm.tm_sec = 0;
1847 }
1848 /*
1849 ** Do a binary search (this works whatever time_t's type is).
1850 */
1851 if (!TYPE_SIGNED(time_t)) {
1852 lo = 0;
1853 hi = lo - 1;
1854 } else if (!TYPE_INTEGRAL(time_t)) {
1855 if (sizeof(time_t) > sizeof(float))
1856 hi = (time_t) DBL_MAX;
1857 else hi = (time_t) FLT_MAX;
1858 lo = -hi;
1859 } else {
1860 lo = 1;
1861 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
1862 lo *= 2;
1863 hi = -(lo + 1);
1864 }
1865 for ( ; ; ) {
1866 t = lo / 2 + hi / 2;
1867 if (t < lo)
1868 t = lo;
1869 else if (t > hi)
1870 t = hi;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001871 if ((*funcp)(&t, offset, &mytm, sp) == NULL) { // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001872 /*
1873 ** Assume that t is too extreme to be represented in
1874 ** a struct tm; arrange things so that it is less
1875 ** extreme on the next pass.
1876 */
1877 dir = (t > 0) ? 1 : -1;
1878 } else dir = tmcomp(&mytm, &yourtm);
1879 if (dir != 0) {
1880 if (t == lo) {
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001881 if (t == TIME_T_MAX)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001882 return WRONG;
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001883 ++t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001884 ++lo;
1885 } else if (t == hi) {
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001886 if (t == TIME_T_MIN)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001887 return WRONG;
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001888 --t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001889 --hi;
1890 }
1891 if (lo > hi)
1892 return WRONG;
1893 if (dir > 0)
1894 hi = t;
1895 else lo = t;
1896 continue;
1897 }
1898 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1899 break;
1900 /*
1901 ** Right time, wrong type.
1902 ** Hunt for right time, right type.
1903 ** It's okay to guess wrong since the guess
1904 ** gets checked.
1905 */
1906 /*
1907 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1908 */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001909 // BEGIN android-changed: support user-supplied sp
1910 if (sp == NULL) {
1911 sp = (const struct state *)
1912 (((void *) funcp == (void *) localsub) ?
1913 lclptr : gmtptr);
1914 }
1915 // END android-changed
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001916#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001917 if (sp == NULL)
1918 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001919#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001920 for (i = sp->typecnt - 1; i >= 0; --i) {
1921 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1922 continue;
1923 for (j = sp->typecnt - 1; j >= 0; --j) {
1924 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1925 continue;
1926 newt = t + sp->ttis[j].tt_gmtoff -
1927 sp->ttis[i].tt_gmtoff;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001928 if ((*funcp)(&newt, offset, &mytm, sp) == NULL) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001929 continue;
1930 if (tmcomp(&mytm, &yourtm) != 0)
1931 continue;
1932 if (mytm.tm_isdst != yourtm.tm_isdst)
1933 continue;
1934 /*
1935 ** We have a match.
1936 */
1937 t = newt;
1938 goto label;
1939 }
1940 }
1941 return WRONG;
1942 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001943label:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001944 newt = t + saved_seconds;
1945 if ((newt < t) != (saved_seconds < 0))
1946 return WRONG;
1947 t = newt;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001948 if ((*funcp)(&t, offset, tmp, sp)) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001949 *okayp = TRUE;
1950 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001951}
1952
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001953// BEGIN android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001954static time_t
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001955time2(tmp, funcp, offset, okayp, sp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001956struct tm * const tmp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001957struct tm * (* const funcp) P((const time_t*, long, struct tm*, const struct state*));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001958const long offset;
1959int * const okayp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001960const struct state * sp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001961{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001962 time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001963
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001964 /*
1965 ** First try without normalization of seconds
1966 ** (in case tm_sec contains a value associated with a leap second).
1967 ** If that fails, try with normalization of seconds.
1968 */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001969 t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
1970 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001971}
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001972// END android-changed
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001973
1974static time_t
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001975time1(tmp, funcp, offset, sp) // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001976struct tm * const tmp;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001977struct tm * (* const funcp) P((const time_t *, long, struct tm *, const struct state *));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001978const long offset;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001979const struct state * sp; // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001980{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001981 register time_t t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001982 register int samei, otheri;
1983 register int sameind, otherind;
1984 register int i;
1985 register int nseen;
1986 int seen[TZ_MAX_TYPES];
1987 int types[TZ_MAX_TYPES];
1988 int okay;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001989
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001990 if (tmp->tm_isdst > 1)
1991 tmp->tm_isdst = 1;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08001992 t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001993#ifdef PCTS
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001994 /*
1995 ** PCTS code courtesy Grant Sullivan.
1996 */
1997 if (okay)
1998 return t;
1999 if (tmp->tm_isdst < 0)
2000 tmp->tm_isdst = 0; /* reset to std and try again */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002001#endif /* defined PCTS */
2002#ifndef PCTS
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002003 if (okay || tmp->tm_isdst < 0)
2004 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002005#endif /* !defined PCTS */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002006 /*
2007 ** We're supposed to assume that somebody took a time of one type
2008 ** and did some math on it that yielded a "struct tm" that's bad.
2009 ** We try to divine the type they started from and adjust to the
2010 ** type they need.
2011 */
2012 /*
2013 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
2014 */
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002015 // BEGIN android-changed: support user-supplied sp.
2016 if (sp == NULL) {
2017 sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
2018 lclptr : gmtptr);
2019 }
2020 // BEGIN android-changed
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002021#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002022 if (sp == NULL)
2023 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002024#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002025 for (i = 0; i < sp->typecnt; ++i)
2026 seen[i] = FALSE;
2027 nseen = 0;
2028 for (i = sp->timecnt - 1; i >= 0; --i)
2029 if (!seen[sp->types[i]]) {
2030 seen[sp->types[i]] = TRUE;
2031 types[nseen++] = sp->types[i];
2032 }
2033 for (sameind = 0; sameind < nseen; ++sameind) {
2034 samei = types[sameind];
2035 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2036 continue;
2037 for (otherind = 0; otherind < nseen; ++otherind) {
2038 otheri = types[otherind];
2039 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2040 continue;
2041 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
2042 sp->ttis[samei].tt_gmtoff;
2043 tmp->tm_isdst = !tmp->tm_isdst;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002044 t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002045 if (okay)
2046 return t;
2047 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
2048 sp->ttis[samei].tt_gmtoff;
2049 tmp->tm_isdst = !tmp->tm_isdst;
2050 }
2051 }
2052 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002053}
2054
2055time_t
2056mktime(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002057struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002058{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002059 time_t result;
2060 _tzLock();
2061 tzset_locked();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002062 result = time1(tmp, localsub, 0L, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002063 _tzUnlock();
2064 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002065}
2066
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002067// BEGIN android-added
Elliott Hughes4a05bef2013-03-11 17:17:02 -07002068
2069// Caches the most recent timezone (http://b/8270865).
2070static int __bionic_tzload_cached(const char* name, struct state* const sp, const int doextend) {
2071 _tzLock();
2072
2073 // Our single-item cache.
2074 static char* gCachedTimeZoneName;
2075 static struct state gCachedTimeZone;
2076
2077 // Do we already have this timezone cached?
2078 if (gCachedTimeZoneName != NULL && strcmp(name, gCachedTimeZoneName) == 0) {
2079 *sp = gCachedTimeZone;
2080 _tzUnlock();
2081 return 0;
2082 }
2083
2084 // Can we load it?
2085 int rc = tzload(name, sp, doextend);
2086 if (rc == 0) {
2087 // Update the cache.
2088 free(gCachedTimeZoneName);
2089 gCachedTimeZoneName = strdup(name);
2090 gCachedTimeZone = *sp;
2091 }
2092
2093 _tzUnlock();
2094 return rc;
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002095}
2096
Elliott Hughes4a05bef2013-03-11 17:17:02 -07002097// Non-standard API: mktime(3) but with an explicit timezone parameter.
2098time_t mktime_tz(struct tm* const tmp, const char* tz) {
2099 struct state st;
2100 if (__bionic_tzload_cached(tz, &st, TRUE) != 0) {
2101 // TODO: not sure what's best here, but for now, we fall back to gmt.
2102 gmtload(&st);
2103 }
2104 return time1(tmp, localsub, 0L, &st);
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002105}
Elliott Hughes4a05bef2013-03-11 17:17:02 -07002106
2107// Non-standard API: localtime(3) but with an explicit timezone parameter.
2108void localtime_tz(const time_t* const timep, struct tm* tmp, const char* tz) {
2109 struct state st;
2110 if (__bionic_tzload_cached(tz, &st, TRUE) != 0) {
2111 // TODO: not sure what's best here, but for now, we fall back to gmt.
2112 gmtload(&st);
2113 }
2114 localsub(timep, 0L, tmp, &st);
2115}
2116
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002117// END android-added
2118
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002119#ifdef STD_INSPIRED
2120
2121time_t
2122timelocal(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002123struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002124{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002125 tmp->tm_isdst = -1; /* in case it wasn't initialized */
2126 return mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002127}
2128
2129time_t
2130timegm(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002131struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002132{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002133 time_t result;
2134
2135 tmp->tm_isdst = 0;
2136 _tzLock();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002137 result = time1(tmp, gmtsub, 0L, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002138 _tzUnlock();
2139
2140 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002141}
2142
David 'Digit' Turner6481b912010-12-06 12:23:16 +01002143#if 0 /* disable due to lack of clear documentation on this function */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002144time_t
2145timeoff(tmp, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002146struct tm * const tmp;
2147const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002148{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002149 time_t result;
2150
2151 tmp->tm_isdst = 0;
2152 _tzLock();
Elliott Hughesb989c9c2013-01-16 10:34:33 -08002153 result = time1(tmp, gmtsub, offset, NULL); // android-changed: extra parameter.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002154 _tzUnlock();
2155
2156 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002157}
David 'Digit' Turner6481b912010-12-06 12:23:16 +01002158#endif /* 0 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002159
2160#endif /* defined STD_INSPIRED */
2161
2162#ifdef CMUCS
2163
2164/*
2165** The following is supplied for compatibility with
2166** previous versions of the CMUCS runtime library.
2167*/
2168
2169long
2170gtime(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002171struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002172{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002173 const time_t t = mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002174
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002175 if (t == WRONG)
2176 return -1;
2177 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002178}
2179
2180#endif /* defined CMUCS */
2181
2182/*
2183** XXX--is the below the right way to conditionalize??
2184*/
2185
2186#ifdef STD_INSPIRED
2187
2188/*
2189** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2190** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2191** is not the case if we are accounting for leap seconds.
2192** So, we provide the following conversion routines for use
2193** when exchanging timestamps with POSIX conforming systems.
2194*/
2195
2196static long
2197leapcorr(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002198time_t * timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002199{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002200 register struct state * sp;
2201 register struct lsinfo * lp;
2202 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002203
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002204 sp = lclptr;
2205 i = sp->leapcnt;
2206 while (--i >= 0) {
2207 lp = &sp->lsis[i];
2208 if (*timep >= lp->ls_trans)
2209 return lp->ls_corr;
2210 }
2211 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002212}
2213
2214time_t
2215time2posix(t)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002216time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002217{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002218 tzset();
2219 return t - leapcorr(&t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002220}
2221
2222time_t
2223posix2time(t)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002224time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002225{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002226 time_t x;
2227 time_t y;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002228
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002229 tzset();
2230 /*
2231 ** For a positive leap second hit, the result
2232 ** is not unique. For a negative leap second
2233 ** hit, the corresponding time doesn't exist,
2234 ** so we return an adjacent second.
2235 */
2236 x = t + leapcorr(&t);
2237 y = x - leapcorr(&x);
2238 if (y < t) {
2239 do {
2240 x++;
2241 y = x - leapcorr(&x);
2242 } while (y < t);
2243 if (t != y)
2244 return x - 1;
2245 } else if (y > t) {
2246 do {
2247 --x;
2248 y = x - leapcorr(&x);
2249 } while (y > t);
2250 if (t != y)
2251 return x + 1;
2252 }
2253 return x;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002254}
2255
2256#endif /* defined STD_INSPIRED */
Elliott Hughesd23af232012-10-17 16:30:47 -07002257
Elliott Hughes1c295722012-10-19 18:13:15 -07002258#include <assert.h>
Elliott Hughesd23af232012-10-17 16:30:47 -07002259#include <stdint.h>
Elliott Hughes8b954042012-10-18 13:42:59 -07002260#include <arpa/inet.h> // For ntohl(3).
Elliott Hughesd23af232012-10-17 16:30:47 -07002261
Elliott Hughes1c295722012-10-19 18:13:15 -07002262static int __bionic_open_tzdata_path(const char* path, const char* olson_id, int* data_size) {
2263 int fd = TEMP_FAILURE_RETRY(open(path, OPEN_MODE));
Elliott Hughesd23af232012-10-17 16:30:47 -07002264 if (fd == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002265 XLOG(("%s: could not open \"%s\": %s\n", __FUNCTION__, path, strerror(errno)));
2266 return -2; // Distinguish failure to find any data from failure to find a specific id.
Elliott Hughesd23af232012-10-17 16:30:47 -07002267 }
2268
2269 // byte[12] tzdata_version -- "tzdata2012f\0"
Elliott Hughesd23af232012-10-17 16:30:47 -07002270 // int index_offset
2271 // int data_offset
2272 // int zonetab_offset
2273 struct bionic_tzdata_header {
2274 char tzdata_version[12];
Elliott Hughesd23af232012-10-17 16:30:47 -07002275 int32_t index_offset;
2276 int32_t data_offset;
2277 int32_t zonetab_offset;
2278 } header;
2279 if (TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header))) != sizeof(header)) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002280 fprintf(stderr, "%s: could not read header: %s\n", __FUNCTION__, strerror(errno));
Elliott Hughesd23af232012-10-17 16:30:47 -07002281 close(fd);
2282 return -1;
2283 }
2284
2285 if (strncmp(header.tzdata_version, "tzdata", 6) != 0 || header.tzdata_version[11] != 0) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002286 fprintf(stderr, "%s: bad magic: %s\n", __FUNCTION__, header.tzdata_version);
Elliott Hughesd23af232012-10-17 16:30:47 -07002287 close(fd);
2288 return -1;
2289 }
Elliott Hughesd23af232012-10-17 16:30:47 -07002290
2291#if 0
Elliott Hughes23935352012-10-22 14:47:58 -07002292 fprintf(stderr, "version: %s\n", header.tzdata_version);
Elliott Hughesd23af232012-10-17 16:30:47 -07002293 fprintf(stderr, "index_offset = %d\n", ntohl(header.index_offset));
2294 fprintf(stderr, "data_offset = %d\n", ntohl(header.data_offset));
2295 fprintf(stderr, "zonetab_offset = %d\n", ntohl(header.zonetab_offset));
2296#endif
2297
2298 if (TEMP_FAILURE_RETRY(lseek(fd, ntohl(header.index_offset), SEEK_SET)) == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002299 fprintf(stderr, "%s: couldn't seek to index: %s\n", __FUNCTION__, strerror(errno));
Elliott Hughesd23af232012-10-17 16:30:47 -07002300 close(fd);
2301 return -1;
2302 }
2303
2304 off_t specific_zone_offset = -1;
2305
Elliott Hughes1c295722012-10-19 18:13:15 -07002306 static const size_t NAME_LENGTH = 40;
2307 unsigned char buf[NAME_LENGTH + 3 * sizeof(int32_t)];
Elliott Hughese0175ca2013-03-14 14:38:08 -07002308
2309 size_t id_count = (ntohl(header.data_offset) - ntohl(header.index_offset)) / sizeof(buf);
2310 for (size_t i = 0; i < id_count; ++i) {
2311 if (TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf))) != (ssize_t) sizeof(buf)) {
2312 break;
2313 }
2314
Elliott Hughes1c295722012-10-19 18:13:15 -07002315 char this_id[NAME_LENGTH + 1];
2316 memcpy(this_id, buf, NAME_LENGTH);
2317 this_id[NAME_LENGTH] = '\0';
Elliott Hughesd23af232012-10-17 16:30:47 -07002318
2319 if (strcmp(this_id, olson_id) == 0) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002320 specific_zone_offset = toint(buf + NAME_LENGTH) + ntohl(header.data_offset);
2321 *data_size = toint(buf + NAME_LENGTH + sizeof(int32_t));
Elliott Hughesd23af232012-10-17 16:30:47 -07002322 break;
2323 }
2324 }
2325
2326 if (specific_zone_offset == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002327 XLOG(("%s: couldn't find zone \"%s\"\n", __FUNCTION__, olson_id));
Elliott Hughesd23af232012-10-17 16:30:47 -07002328 close(fd);
2329 return -1;
2330 }
2331
2332 if (TEMP_FAILURE_RETRY(lseek(fd, specific_zone_offset, SEEK_SET)) == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002333 fprintf(stderr, "%s: could not seek to %ld: %s\n", __FUNCTION__, specific_zone_offset, strerror(errno));
Elliott Hughesd23af232012-10-17 16:30:47 -07002334 close(fd);
2335 return -1;
2336 }
2337
2338 return fd;
2339}
Elliott Hughes1c295722012-10-19 18:13:15 -07002340
2341static int __bionic_open_tzdata(const char* olson_id, int* data_size) {
2342 // TODO: use $ANDROID_DATA and $ANDROID_ROOT like libcore, to support bionic on the host.
2343 int fd = __bionic_open_tzdata_path("/data/misc/zoneinfo/tzdata", olson_id, data_size);
2344 if (fd < 0) {
2345 fd = __bionic_open_tzdata_path("/system/usr/share/zoneinfo/tzdata", olson_id, data_size);
2346 if (fd == -2) {
Elliott Hughes49271d82012-10-25 14:38:51 -07002347 // The first thing that 'recovery' does is try to format the current time. It doesn't have
2348 // any tzdata available, so we must not abort here --- doing so breaks the recovery image!
2349 fprintf(stderr, "%s: couldn't find any tzdata when looking for %s!\n", __FUNCTION__, olson_id);
Elliott Hughes1c295722012-10-19 18:13:15 -07002350 }
2351 }
2352 return fd;
2353}