blob: 6ed36c8c9b56bcdc3b42dea23080a6e5dd734a28 [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 Hughesf4b34b62012-09-24 10:13:12 -0700215 struct tm * tmp));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700216static struct tm * localsub P((const time_t * timep, long offset,
Elliott Hughesf4b34b62012-09-24 10:13:12 -0700217 struct tm * tmp));
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 Hughesf4b34b62012-09-24 10:13:12 -0700228 long, struct tm *)),
229 long offset));
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 Hughesf4b34b62012-09-24 10:13:12 -0700232 long, struct tm*)),
233 long offset, int * okayp));
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 Hughesf4b34b62012-09-24 10:13:12 -0700236 long, struct tm*)),
237 long offset, int * okayp, int do_norm_secs));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700238static struct tm * timesub P((const time_t * timep, long offset,
239 const struct state * sp, struct tm * tmp));
240static int tmcomp P((const struct tm * atmp,
241 const struct tm * btmp));
242static time_t transtime P((time_t janfirst, int year,
243 const struct rule * rulep, long offset));
244static int tzload P((const char * name, struct state * sp,
245 int doextend));
246static int tzparse P((const char * name, struct state * sp,
247 int lastditch));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800248
249#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700250static struct state * lclptr;
251static struct state * gmtptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800252#endif /* defined ALL_STATE */
253
254#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700255static struct state lclmem;
256static struct state gmtmem;
257#define lclptr (&lclmem)
258#define gmtptr (&gmtmem)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800259#endif /* State Farm */
260
261#ifndef TZ_STRLEN_MAX
262#define TZ_STRLEN_MAX 255
263#endif /* !defined TZ_STRLEN_MAX */
264
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700265static char lcl_TZname[TZ_STRLEN_MAX + 1];
266static int lcl_is_set;
267static int gmt_is_set;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800268
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700269char * tzname[2] = {
270 wildabbr,
271 wildabbr
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800272};
273
274/*
275** Section 4.12.3 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700276** Except for the strftime function, these functions [asctime,
277** ctime, gmtime, localtime] return values in one of two static
278** objects: a broken-down time structure and an array of char.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800279** Thanks to Paul Eggert for noting this.
280*/
281
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700282static struct tm tmGlobal;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800283
284#ifdef USG_COMPAT
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700285time_t timezone = 0;
286int daylight = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800287#endif /* defined USG_COMPAT */
288
289#ifdef ALTZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700290time_t altzone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800291#endif /* defined ALTZONE */
292
293static long
294detzcode(codep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700295const char * const codep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800296{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700297 register long result;
298 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800299
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700300 result = (codep[0] & 0x80) ? ~0L : 0;
301 for (i = 0; i < 4; ++i)
302 result = (result << 8) | (codep[i] & 0xff);
303 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800304}
305
306static time_t
307detzcode64(codep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700308const char * const codep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800309{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700310 register time_t result;
311 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800312
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700313 result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0;
314 for (i = 0; i < 8; ++i)
315 result = result * 256 + (codep[i] & 0xff);
316 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800317}
318
319static void
320settzname P((void))
321{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700322 register struct state * const sp = lclptr;
323 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800324
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700325 tzname[0] = wildabbr;
326 tzname[1] = wildabbr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800327#ifdef USG_COMPAT
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700328 daylight = 0;
329 timezone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800330#endif /* defined USG_COMPAT */
331#ifdef ALTZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700332 altzone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800333#endif /* defined ALTZONE */
334#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700335 if (sp == NULL) {
336 tzname[0] = tzname[1] = gmt;
337 return;
338 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800339#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700340 for (i = 0; i < sp->typecnt; ++i) {
341 register const struct ttinfo * const ttisp = &sp->ttis[i];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800342
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700343 tzname[ttisp->tt_isdst] =
344 &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800345#ifdef USG_COMPAT
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700346 if (ttisp->tt_isdst)
347 daylight = 1;
348 if (i == 0 || !ttisp->tt_isdst)
349 timezone = -(ttisp->tt_gmtoff);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800350#endif /* defined USG_COMPAT */
351#ifdef ALTZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700352 if (i == 0 || ttisp->tt_isdst)
353 altzone = -(ttisp->tt_gmtoff);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800354#endif /* defined ALTZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700355 }
356 /*
357 ** And to get the latest zone names into tzname. . .
358 */
359 for (i = 0; i < sp->timecnt; ++i) {
360 register const struct ttinfo * const ttisp =
361 &sp->ttis[
362 sp->types[i]];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800363
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700364 tzname[ttisp->tt_isdst] =
365 &sp->chars[ttisp->tt_abbrind];
366 }
367 /*
368 ** Finally, scrub the abbreviations.
369 ** First, replace bogus characters.
370 */
371 for (i = 0; i < sp->charcnt; ++i)
372 if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
373 sp->chars[i] = TZ_ABBR_ERR_CHAR;
374 /*
375 ** Second, truncate long abbreviations.
376 */
377 for (i = 0; i < sp->typecnt; ++i) {
378 register const struct ttinfo * const ttisp = &sp->ttis[i];
379 register char * cp = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800380
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700381 if (strlen(cp) > TZ_ABBR_MAX_LEN &&
382 strcmp(cp, GRANDPARENTED) != 0)
383 *(cp + TZ_ABBR_MAX_LEN) = '\0';
384 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800385}
386
387static int
388differ_by_repeat(t1, t0)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700389const time_t t1;
390const time_t t0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800391{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700392 if (TYPE_INTEGRAL(time_t) &&
393 TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
394 return 0;
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700395#if SECSPERREPEAT_BITS <= 32 /* to avoid compiler warning (condition is always false) */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800396 return (t1 - t0) == SECSPERREPEAT;
David 'Digit' Turner50ace4f2010-06-16 16:36:41 -0700397#else
398 return 0;
399#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800400}
401
402static int toint(unsigned char *s) {
403 return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
404}
405
406static int
407tzload(name, sp, doextend)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700408register const char * name;
409register struct state * const sp;
410register const int doextend;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800411{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700412 register const char * p;
413 register int i;
414 register int fid;
415 register int stored;
416 register int nread;
417 union {
418 struct tzhead tzhead;
419 char buf[2 * sizeof(struct tzhead) +
420 2 * sizeof *sp +
421 4 * TZ_MAX_TIMES];
422 } u;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800423 int toread = sizeof u.buf;
424
425 if (name == NULL && (name = TZDEFAULT) == NULL) {
426 XLOG(("tzload: null 'name' parameter\n" ));
427 return -1;
428 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700429 {
430 register int doaccess;
431 /*
432 ** Section 4.9.1 of the C standard says that
433 ** "FILENAME_MAX expands to an integral constant expression
434 ** that is the size needed for an array of char large enough
435 ** to hold the longest file name string that the implementation
436 ** guarantees can be opened."
437 */
438 char fullname[FILENAME_MAX + 1];
439 char *origname = (char*) name;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800440
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700441 if (name[0] == ':')
442 ++name;
443 doaccess = name[0] == '/';
444 if (!doaccess) {
445 if ((p = TZDIR) == NULL) {
446 XLOG(("tzload: null TZDIR macro ?\n" ));
447 return -1;
448 }
449 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) {
450 XLOG(( "tzload: path too long: %s/%s\n", p, name ));
451 return -1;
452 }
453 (void) strcpy(fullname, p);
454 (void) strcat(fullname, "/");
455 (void) strcat(fullname, name);
456 /*
457 ** Set doaccess if '.' (as in "../") shows up in name.
458 */
459 if (strchr(name, '.') != NULL)
460 doaccess = TRUE;
461 name = fullname;
462 }
463 if (doaccess && access(name, R_OK) != 0) {
464 XLOG(( "tzload: could not find '%s'\n", name ));
465 return -1;
466 }
467 if ((fid = open(name, OPEN_MODE)) == -1) {
Elliott Hughesd23af232012-10-17 16:30:47 -0700468 fid = __bionic_open_tzdata(origname, &toread);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800469 if (fid < 0) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800470 return -1;
471 }
472 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700473 }
474 nread = read(fid, u.buf, toread);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800475 if (close(fid) < 0 || nread <= 0) {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700476 XLOG(( "tzload: could not read content of '%s'\n", DATAFILE ));
477 return -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800478 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700479 for (stored = 4; stored <= 8; stored *= 2) {
480 int ttisstdcnt;
481 int ttisgmtcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800482
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700483 ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
484 ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
485 sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
486 sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
487 sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
488 sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
489 p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
490 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
491 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
492 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
493 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
494 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
495 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
496 return -1;
497 if (nread - (p - u.buf) <
498 sp->timecnt * stored + /* ats */
499 sp->timecnt + /* types */
500 sp->typecnt * 6 + /* ttinfos */
501 sp->charcnt + /* chars */
502 sp->leapcnt * (stored + 4) + /* lsinfos */
503 ttisstdcnt + /* ttisstds */
504 ttisgmtcnt) /* ttisgmts */
505 return -1;
506 for (i = 0; i < sp->timecnt; ++i) {
507 sp->ats[i] = (stored == 4) ?
508 detzcode(p) : detzcode64(p);
509 p += stored;
510 }
511 for (i = 0; i < sp->timecnt; ++i) {
512 sp->types[i] = (unsigned char) *p++;
513 if (sp->types[i] >= sp->typecnt)
514 return -1;
515 }
516 for (i = 0; i < sp->typecnt; ++i) {
517 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800518
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700519 ttisp = &sp->ttis[i];
520 ttisp->tt_gmtoff = detzcode(p);
521 p += 4;
522 ttisp->tt_isdst = (unsigned char) *p++;
523 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
524 return -1;
525 ttisp->tt_abbrind = (unsigned char) *p++;
526 if (ttisp->tt_abbrind < 0 ||
527 ttisp->tt_abbrind > sp->charcnt)
528 return -1;
529 }
530 for (i = 0; i < sp->charcnt; ++i)
531 sp->chars[i] = *p++;
532 sp->chars[i] = '\0'; /* ensure '\0' at end */
533 for (i = 0; i < sp->leapcnt; ++i) {
534 register struct lsinfo * lsisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800535
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700536 lsisp = &sp->lsis[i];
537 lsisp->ls_trans = (stored == 4) ?
538 detzcode(p) : detzcode64(p);
539 p += stored;
540 lsisp->ls_corr = detzcode(p);
541 p += 4;
542 }
543 for (i = 0; i < sp->typecnt; ++i) {
544 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800545
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700546 ttisp = &sp->ttis[i];
547 if (ttisstdcnt == 0)
548 ttisp->tt_ttisstd = FALSE;
549 else {
550 ttisp->tt_ttisstd = *p++;
551 if (ttisp->tt_ttisstd != TRUE &&
552 ttisp->tt_ttisstd != FALSE)
553 return -1;
554 }
555 }
556 for (i = 0; i < sp->typecnt; ++i) {
557 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800558
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700559 ttisp = &sp->ttis[i];
560 if (ttisgmtcnt == 0)
561 ttisp->tt_ttisgmt = FALSE;
562 else {
563 ttisp->tt_ttisgmt = *p++;
564 if (ttisp->tt_ttisgmt != TRUE &&
565 ttisp->tt_ttisgmt != FALSE)
566 return -1;
567 }
568 }
569 /*
570 ** Out-of-sort ats should mean we're running on a
571 ** signed time_t system but using a data file with
572 ** unsigned values (or vice versa).
573 */
574 for (i = 0; i < sp->timecnt - 2; ++i)
575 if (sp->ats[i] > sp->ats[i + 1]) {
576 ++i;
577 if (TYPE_SIGNED(time_t)) {
578 /*
579 ** Ignore the end (easy).
580 */
581 sp->timecnt = i;
582 } else {
583 /*
584 ** Ignore the beginning (harder).
585 */
586 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800587
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700588 for (j = 0; j + i < sp->timecnt; ++j) {
589 sp->ats[j] = sp->ats[j + i];
590 sp->types[j] = sp->types[j + i];
591 }
592 sp->timecnt = j;
593 }
594 break;
595 }
596 /*
597 ** If this is an old file, we're done.
598 */
599 if (u.tzhead.tzh_version[0] == '\0')
600 break;
601 nread -= p - u.buf;
602 for (i = 0; i < nread; ++i)
603 u.buf[i] = p[i];
604 /*
605 ** If this is a narrow integer time_t system, we're done.
606 */
607 if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
608 break;
609 }
610 if (doextend && nread > 2 &&
611 u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
612 sp->typecnt + 2 <= TZ_MAX_TYPES) {
613 struct state ts;
614 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800615
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700616 u.buf[nread - 1] = '\0';
617 result = tzparse(&u.buf[1], &ts, FALSE);
618 if (result == 0 && ts.typecnt == 2 &&
619 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
620 for (i = 0; i < 2; ++i)
621 ts.ttis[i].tt_abbrind +=
622 sp->charcnt;
623 for (i = 0; i < ts.charcnt; ++i)
624 sp->chars[sp->charcnt++] =
625 ts.chars[i];
626 i = 0;
627 while (i < ts.timecnt &&
628 ts.ats[i] <=
629 sp->ats[sp->timecnt - 1])
630 ++i;
631 while (i < ts.timecnt &&
632 sp->timecnt < TZ_MAX_TIMES) {
633 sp->ats[sp->timecnt] =
634 ts.ats[i];
635 sp->types[sp->timecnt] =
636 sp->typecnt +
637 ts.types[i];
638 ++sp->timecnt;
639 ++i;
640 }
641 sp->ttis[sp->typecnt++] = ts.ttis[0];
642 sp->ttis[sp->typecnt++] = ts.ttis[1];
643 }
644 }
645 i = 2 * YEARSPERREPEAT;
646 sp->goback = sp->goahead = sp->timecnt > i;
647 sp->goback &= sp->types[i] == sp->types[0] &&
648 differ_by_repeat(sp->ats[i], sp->ats[0]);
649 sp->goahead &=
650 sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
651 differ_by_repeat(sp->ats[sp->timecnt - 1],
652 sp->ats[sp->timecnt - 1 - i]);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800653 XLOG(( "tzload: load ok !!\n" ));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700654 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800655}
656
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700657static const int mon_lengths[2][MONSPERYEAR] = {
658 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
659 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800660};
661
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700662static const int year_lengths[2] = {
663 DAYSPERNYEAR, DAYSPERLYEAR
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800664};
665
666/*
667** Given a pointer into a time zone string, scan until a character that is not
668** a valid character in a zone name is found. Return a pointer to that
669** character.
670*/
671
672static const char *
673getzname(strp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700674register const char * strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800675{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700676 register char c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800677
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700678 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
679 c != '+')
680 ++strp;
681 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800682}
683
684/*
685** Given a pointer into an extended time zone string, scan until the ending
686** delimiter of the zone name is located. Return a pointer to the delimiter.
687**
688** As with getzname above, the legal character set is actually quite
689** restricted, with other characters producing undefined results.
690** We don't do any checking here; checking is done later in common-case code.
691*/
692
693static const char *
694getqzname(register const char *strp, const int delim)
695{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700696 register int c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800697
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700698 while ((c = *strp) != '\0' && c != delim)
699 ++strp;
700 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800701}
702
703/*
704** Given a pointer into a time zone string, extract a number from that string.
705** Check that the number is within a specified range; if it is not, return
706** NULL.
707** Otherwise, return a pointer to the first character not part of the number.
708*/
709
710static const char *
711getnum(strp, nump, min, max)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700712register const char * strp;
713int * const nump;
714const int min;
715const int max;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800716{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700717 register char c;
718 register int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800719
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700720 if (strp == NULL || !is_digit(c = *strp))
721 return NULL;
722 num = 0;
723 do {
724 num = num * 10 + (c - '0');
725 if (num > max)
726 return NULL; /* illegal value */
727 c = *++strp;
728 } while (is_digit(c));
729 if (num < min)
730 return NULL; /* illegal value */
731 *nump = num;
732 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800733}
734
735/*
736** Given a pointer into a time zone string, extract a number of seconds,
737** in hh[:mm[:ss]] form, from the string.
738** If any error occurs, return NULL.
739** Otherwise, return a pointer to the first character not part of the number
740** of seconds.
741*/
742
743static const char *
744getsecs(strp, secsp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700745register const char * strp;
746long * const secsp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800747{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700748 int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800749
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700750 /*
751 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
752 ** "M10.4.6/26", which does not conform to Posix,
753 ** but which specifies the equivalent of
754 ** ``02:00 on the first Sunday on or after 23 Oct''.
755 */
756 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
757 if (strp == NULL)
758 return NULL;
759 *secsp = num * (long) SECSPERHOUR;
760 if (*strp == ':') {
761 ++strp;
762 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
763 if (strp == NULL)
764 return NULL;
765 *secsp += num * SECSPERMIN;
766 if (*strp == ':') {
767 ++strp;
768 /* `SECSPERMIN' allows for leap seconds. */
769 strp = getnum(strp, &num, 0, SECSPERMIN);
770 if (strp == NULL)
771 return NULL;
772 *secsp += num;
773 }
774 }
775 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800776}
777
778/*
779** Given a pointer into a time zone string, extract an offset, in
780** [+-]hh[:mm[:ss]] form, from the string.
781** If any error occurs, return NULL.
782** Otherwise, return a pointer to the first character not part of the time.
783*/
784
785static const char *
786getoffset(strp, offsetp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700787register const char * strp;
788long * const offsetp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800789{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700790 register int neg = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800791
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700792 if (*strp == '-') {
793 neg = 1;
794 ++strp;
795 } else if (*strp == '+')
796 ++strp;
797 strp = getsecs(strp, offsetp);
798 if (strp == NULL)
799 return NULL; /* illegal time */
800 if (neg)
801 *offsetp = -*offsetp;
802 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800803}
804
805/*
806** Given a pointer into a time zone string, extract a rule in the form
807** date[/time]. See POSIX section 8 for the format of "date" and "time".
808** If a valid rule is not found, return NULL.
809** Otherwise, return a pointer to the first character not part of the rule.
810*/
811
812static const char *
813getrule(strp, rulep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700814const char * strp;
815register struct rule * const rulep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800816{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700817 if (*strp == 'J') {
818 /*
819 ** Julian day.
820 */
821 rulep->r_type = JULIAN_DAY;
822 ++strp;
823 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
824 } else if (*strp == 'M') {
825 /*
826 ** Month, week, day.
827 */
828 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
829 ++strp;
830 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
831 if (strp == NULL)
832 return NULL;
833 if (*strp++ != '.')
834 return NULL;
835 strp = getnum(strp, &rulep->r_week, 1, 5);
836 if (strp == NULL)
837 return NULL;
838 if (*strp++ != '.')
839 return NULL;
840 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
841 } else if (is_digit(*strp)) {
842 /*
843 ** Day of year.
844 */
845 rulep->r_type = DAY_OF_YEAR;
846 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
847 } else return NULL; /* invalid format */
848 if (strp == NULL)
849 return NULL;
850 if (*strp == '/') {
851 /*
852 ** Time specified.
853 */
854 ++strp;
855 strp = getsecs(strp, &rulep->r_time);
856 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
857 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800858}
859
860/*
861** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
862** year, a rule, and the offset from UTC at the time that rule takes effect,
863** calculate the Epoch-relative time that rule takes effect.
864*/
865
866static time_t
867transtime(janfirst, year, rulep, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700868const time_t janfirst;
869const int year;
870register const struct rule * const rulep;
871const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800872{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700873 register int leapyear;
874 register time_t value;
875 register int i;
876 int d, m1, yy0, yy1, yy2, dow;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800877
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700878 INITIALIZE(value);
879 leapyear = isleap(year);
880 switch (rulep->r_type) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800881
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700882 case JULIAN_DAY:
883 /*
884 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
885 ** years.
886 ** In non-leap years, or if the day number is 59 or less, just
887 ** add SECSPERDAY times the day number-1 to the time of
888 ** January 1, midnight, to get the day.
889 */
890 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
891 if (leapyear && rulep->r_day >= 60)
892 value += SECSPERDAY;
893 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800894
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700895 case DAY_OF_YEAR:
896 /*
897 ** n - day of year.
898 ** Just add SECSPERDAY times the day number to the time of
899 ** January 1, midnight, to get the day.
900 */
901 value = janfirst + rulep->r_day * SECSPERDAY;
902 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800903
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700904 case MONTH_NTH_DAY_OF_WEEK:
905 /*
906 ** Mm.n.d - nth "dth day" of month m.
907 */
908 value = janfirst;
909 for (i = 0; i < rulep->r_mon - 1; ++i)
910 value += mon_lengths[leapyear][i] * SECSPERDAY;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800911
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700912 /*
913 ** Use Zeller's Congruence to get day-of-week of first day of
914 ** month.
915 */
916 m1 = (rulep->r_mon + 9) % 12 + 1;
917 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
918 yy1 = yy0 / 100;
919 yy2 = yy0 % 100;
920 dow = ((26 * m1 - 2) / 10 +
921 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
922 if (dow < 0)
923 dow += DAYSPERWEEK;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800924
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700925 /*
926 ** "dow" is the day-of-week of the first day of the month. Get
927 ** the day-of-month (zero-origin) of the first "dow" day of the
928 ** month.
929 */
930 d = rulep->r_day - dow;
931 if (d < 0)
932 d += DAYSPERWEEK;
933 for (i = 1; i < rulep->r_week; ++i) {
934 if (d + DAYSPERWEEK >=
935 mon_lengths[leapyear][rulep->r_mon - 1])
936 break;
937 d += DAYSPERWEEK;
938 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800939
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700940 /*
941 ** "d" is the day-of-month (zero-origin) of the day we want.
942 */
943 value += d * SECSPERDAY;
944 break;
945 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800946
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700947 /*
948 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
949 ** question. To get the Epoch-relative time of the specified local
950 ** time on that day, add the transition time and the current offset
951 ** from UTC.
952 */
953 return value + rulep->r_time + offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800954}
955
956/*
957** Given a POSIX section 8-style TZ string, fill in the rule tables as
958** appropriate.
959*/
960
961static int
962tzparse(name, sp, lastditch)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700963const char * name;
964register struct state * const sp;
965const int lastditch;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800966{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700967 const char * stdname;
968 const char * dstname;
969 size_t stdlen;
970 size_t dstlen;
971 long stdoffset;
972 long dstoffset;
973 register time_t * atp;
974 register unsigned char * typep;
975 register char * cp;
976 register int load_result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800977
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700978 INITIALIZE(dstname);
979 stdname = name;
980 if (lastditch) {
981 stdlen = strlen(name); /* length of standard zone name */
982 name += stdlen;
983 if (stdlen >= sizeof sp->chars)
984 stdlen = (sizeof sp->chars) - 1;
985 stdoffset = 0;
986 } else {
987 if (*name == '<') {
988 name++;
989 stdname = name;
990 name = getqzname(name, '>');
991 if (*name != '>')
992 return (-1);
993 stdlen = name - stdname;
994 name++;
995 } else {
996 name = getzname(name);
997 stdlen = name - stdname;
998 }
999 if (*name == '\0')
1000 return -1;
1001 name = getoffset(name, &stdoffset);
1002 if (name == NULL)
1003 return -1;
1004 }
1005 load_result = tzload(TZDEFRULES, sp, FALSE);
1006 if (load_result != 0)
1007 sp->leapcnt = 0; /* so, we're off a little */
1008 sp->timecnt = 0;
1009 if (*name != '\0') {
1010 if (*name == '<') {
1011 dstname = ++name;
1012 name = getqzname(name, '>');
1013 if (*name != '>')
1014 return -1;
1015 dstlen = name - dstname;
1016 name++;
1017 } else {
1018 dstname = name;
1019 name = getzname(name);
1020 dstlen = name - dstname; /* length of DST zone name */
1021 }
1022 if (*name != '\0' && *name != ',' && *name != ';') {
1023 name = getoffset(name, &dstoffset);
1024 if (name == NULL)
1025 return -1;
1026 } else dstoffset = stdoffset - SECSPERHOUR;
1027 if (*name == '\0' && load_result != 0)
1028 name = TZDEFRULESTRING;
1029 if (*name == ',' || *name == ';') {
1030 struct rule start;
1031 struct rule end;
1032 register int year;
1033 register time_t janfirst;
1034 time_t starttime;
1035 time_t endtime;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001036
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001037 ++name;
1038 if ((name = getrule(name, &start)) == NULL)
1039 return -1;
1040 if (*name++ != ',')
1041 return -1;
1042 if ((name = getrule(name, &end)) == NULL)
1043 return -1;
1044 if (*name != '\0')
1045 return -1;
1046 sp->typecnt = 2; /* standard time and DST */
1047 /*
1048 ** Two transitions per year, from EPOCH_YEAR forward.
1049 */
1050 sp->ttis[0].tt_gmtoff = -dstoffset;
1051 sp->ttis[0].tt_isdst = 1;
1052 sp->ttis[0].tt_abbrind = stdlen + 1;
1053 sp->ttis[1].tt_gmtoff = -stdoffset;
1054 sp->ttis[1].tt_isdst = 0;
1055 sp->ttis[1].tt_abbrind = 0;
1056 atp = sp->ats;
1057 typep = sp->types;
1058 janfirst = 0;
1059 for (year = EPOCH_YEAR;
1060 sp->timecnt + 2 <= TZ_MAX_TIMES;
1061 ++year) {
1062 time_t newfirst;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001063
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001064 starttime = transtime(janfirst, year, &start,
1065 stdoffset);
1066 endtime = transtime(janfirst, year, &end,
1067 dstoffset);
1068 if (starttime > endtime) {
1069 *atp++ = endtime;
1070 *typep++ = 1; /* DST ends */
1071 *atp++ = starttime;
1072 *typep++ = 0; /* DST begins */
1073 } else {
1074 *atp++ = starttime;
1075 *typep++ = 0; /* DST begins */
1076 *atp++ = endtime;
1077 *typep++ = 1; /* DST ends */
1078 }
1079 sp->timecnt += 2;
1080 newfirst = janfirst;
1081 newfirst += year_lengths[isleap(year)] *
1082 SECSPERDAY;
1083 if (newfirst <= janfirst)
1084 break;
1085 janfirst = newfirst;
1086 }
1087 } else {
1088 register long theirstdoffset;
1089 register long theirdstoffset;
1090 register long theiroffset;
1091 register int isdst;
1092 register int i;
1093 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001094
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001095 if (*name != '\0')
1096 return -1;
1097 /*
1098 ** Initial values of theirstdoffset and theirdstoffset.
1099 */
1100 theirstdoffset = 0;
1101 for (i = 0; i < sp->timecnt; ++i) {
1102 j = sp->types[i];
1103 if (!sp->ttis[j].tt_isdst) {
1104 theirstdoffset =
1105 -sp->ttis[j].tt_gmtoff;
1106 break;
1107 }
1108 }
1109 theirdstoffset = 0;
1110 for (i = 0; i < sp->timecnt; ++i) {
1111 j = sp->types[i];
1112 if (sp->ttis[j].tt_isdst) {
1113 theirdstoffset =
1114 -sp->ttis[j].tt_gmtoff;
1115 break;
1116 }
1117 }
1118 /*
1119 ** Initially we're assumed to be in standard time.
1120 */
1121 isdst = FALSE;
1122 theiroffset = theirstdoffset;
1123 /*
1124 ** Now juggle transition times and types
1125 ** tracking offsets as you do.
1126 */
1127 for (i = 0; i < sp->timecnt; ++i) {
1128 j = sp->types[i];
1129 sp->types[i] = sp->ttis[j].tt_isdst;
1130 if (sp->ttis[j].tt_ttisgmt) {
1131 /* No adjustment to transition time */
1132 } else {
1133 /*
1134 ** If summer time is in effect, and the
1135 ** transition time was not specified as
1136 ** standard time, add the summer time
1137 ** offset to the transition time;
1138 ** otherwise, add the standard time
1139 ** offset to the transition time.
1140 */
1141 /*
1142 ** Transitions from DST to DDST
1143 ** will effectively disappear since
1144 ** POSIX provides for only one DST
1145 ** offset.
1146 */
1147 if (isdst && !sp->ttis[j].tt_ttisstd) {
1148 sp->ats[i] += dstoffset -
1149 theirdstoffset;
1150 } else {
1151 sp->ats[i] += stdoffset -
1152 theirstdoffset;
1153 }
1154 }
1155 theiroffset = -sp->ttis[j].tt_gmtoff;
1156 if (sp->ttis[j].tt_isdst)
1157 theirdstoffset = theiroffset;
1158 else theirstdoffset = theiroffset;
1159 }
1160 /*
1161 ** Finally, fill in ttis.
1162 ** ttisstd and ttisgmt need not be handled.
1163 */
1164 sp->ttis[0].tt_gmtoff = -stdoffset;
1165 sp->ttis[0].tt_isdst = FALSE;
1166 sp->ttis[0].tt_abbrind = 0;
1167 sp->ttis[1].tt_gmtoff = -dstoffset;
1168 sp->ttis[1].tt_isdst = TRUE;
1169 sp->ttis[1].tt_abbrind = stdlen + 1;
1170 sp->typecnt = 2;
1171 }
1172 } else {
1173 dstlen = 0;
1174 sp->typecnt = 1; /* only standard time */
1175 sp->timecnt = 0;
1176 sp->ttis[0].tt_gmtoff = -stdoffset;
1177 sp->ttis[0].tt_isdst = 0;
1178 sp->ttis[0].tt_abbrind = 0;
1179 }
1180 sp->charcnt = stdlen + 1;
1181 if (dstlen != 0)
1182 sp->charcnt += dstlen + 1;
1183 if ((size_t) sp->charcnt > sizeof sp->chars)
1184 return -1;
1185 cp = sp->chars;
1186 (void) strncpy(cp, stdname, stdlen);
1187 cp += stdlen;
1188 *cp++ = '\0';
1189 if (dstlen != 0) {
1190 (void) strncpy(cp, dstname, dstlen);
1191 *(cp + dstlen) = '\0';
1192 }
1193 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001194}
1195
1196static void
1197gmtload(sp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001198struct state * const sp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001199{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001200 if (tzload(gmt, sp, TRUE) != 0)
1201 (void) tzparse(gmt, sp, TRUE);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001202}
1203
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001204static void
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001205tzsetwall P((void))
1206{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001207 if (lcl_is_set < 0)
1208 return;
1209 lcl_is_set = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001210
1211#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001212 if (lclptr == NULL) {
1213 lclptr = (struct state *) malloc(sizeof *lclptr);
1214 if (lclptr == NULL) {
1215 settzname(); /* all we can do */
1216 return;
1217 }
1218 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001219#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001220 if (tzload((char *) NULL, lclptr, TRUE) != 0)
1221 gmtload(lclptr);
1222 settzname();
1223}
1224
1225static void
1226tzset_locked P((void))
1227{
1228 register const char * name = NULL;
1229 static char buf[PROP_VALUE_MAX];
1230
1231 name = getenv("TZ");
1232
1233 // try the "persist.sys.timezone" system property first
1234 if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0)
1235 name = buf;
1236
1237 if (name == NULL) {
1238 tzsetwall();
1239 return;
1240 }
1241
1242 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
1243 return;
1244 lcl_is_set = strlen(name) < sizeof lcl_TZname;
1245 if (lcl_is_set)
1246 (void) strcpy(lcl_TZname, name);
1247
1248#ifdef ALL_STATE
1249 if (lclptr == NULL) {
1250 lclptr = (struct state *) malloc(sizeof *lclptr);
1251 if (lclptr == NULL) {
1252 settzname(); /* all we can do */
1253 return;
1254 }
1255 }
1256#endif /* defined ALL_STATE */
1257 if (*name == '\0') {
1258 /*
1259 ** User wants it fast rather than right.
1260 */
1261 lclptr->leapcnt = 0; /* so, we're off a little */
1262 lclptr->timecnt = 0;
1263 lclptr->typecnt = 0;
1264 lclptr->ttis[0].tt_isdst = 0;
1265 lclptr->ttis[0].tt_gmtoff = 0;
1266 lclptr->ttis[0].tt_abbrind = 0;
1267 (void) strcpy(lclptr->chars, gmt);
1268 } else if (tzload(name, lclptr, TRUE) != 0)
1269 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
1270 (void) gmtload(lclptr);
1271 settzname();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001272}
1273
1274void
1275tzset P((void))
1276{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001277 _tzLock();
1278 tzset_locked();
1279 _tzUnlock();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001280}
1281
1282/*
1283** The easy way to behave "as if no library function calls" localtime
1284** is to not call it--so we drop its guts into "localsub", which can be
1285** freely called. (And no, the PANS doesn't require the above behavior--
1286** but it *is* desirable.)
1287**
1288** The unused offset argument is for the benefit of mktime variants.
1289*/
1290
1291/*ARGSUSED*/
1292static struct tm *
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001293localsub(timep, offset, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001294const time_t * const timep;
1295const long offset;
1296struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001297{
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001298 register struct state * sp;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001299 register const struct ttinfo * ttisp;
1300 register int i;
1301 register struct tm * result;
1302 const time_t t = *timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001303
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001304 sp = lclptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001305#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001306 if (sp == NULL)
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001307 return gmtsub(timep, offset, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001308#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001309 if ((sp->goback && t < sp->ats[0]) ||
1310 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1311 time_t newt = t;
1312 register time_t seconds;
1313 register time_t tcycles;
1314 register int_fast64_t icycles;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001315
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001316 if (t < sp->ats[0])
1317 seconds = sp->ats[0] - t;
1318 else seconds = t - sp->ats[sp->timecnt - 1];
1319 --seconds;
1320 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1321 ++tcycles;
1322 icycles = tcycles;
1323 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1324 return NULL;
1325 seconds = icycles;
1326 seconds *= YEARSPERREPEAT;
1327 seconds *= AVGSECSPERYEAR;
1328 if (t < sp->ats[0])
1329 newt += seconds;
1330 else newt -= seconds;
1331 if (newt < sp->ats[0] ||
1332 newt > sp->ats[sp->timecnt - 1])
1333 return NULL; /* "cannot happen" */
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001334 result = localsub(&newt, offset, tmp);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001335 if (result == tmp) {
1336 register time_t newy;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001337
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001338 newy = tmp->tm_year;
1339 if (t < sp->ats[0])
1340 newy -= icycles * YEARSPERREPEAT;
1341 else newy += icycles * YEARSPERREPEAT;
1342 tmp->tm_year = newy;
1343 if (tmp->tm_year != newy)
1344 return NULL;
1345 }
1346 return result;
1347 }
1348 if (sp->timecnt == 0 || t < sp->ats[0]) {
1349 i = 0;
1350 while (sp->ttis[i].tt_isdst)
1351 if (++i >= sp->typecnt) {
1352 i = 0;
1353 break;
1354 }
1355 } else {
1356 register int lo = 1;
1357 register int hi = sp->timecnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001358
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001359 while (lo < hi) {
1360 register int mid = (lo + hi) >> 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001361
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001362 if (t < sp->ats[mid])
1363 hi = mid;
1364 else lo = mid + 1;
1365 }
1366 i = (int) sp->types[lo - 1];
1367 }
1368 ttisp = &sp->ttis[i];
1369 /*
1370 ** To get (wrong) behavior that's compatible with System V Release 2.0
1371 ** you'd replace the statement below with
1372 ** t += ttisp->tt_gmtoff;
1373 ** timesub(&t, 0L, sp, tmp);
1374 */
1375 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1376 tmp->tm_isdst = ttisp->tt_isdst;
1377 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001378#ifdef TM_ZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001379 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001380#endif /* defined TM_ZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001381 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001382}
1383
1384struct tm *
1385localtime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001386const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001387{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001388 return localtime_r(timep, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001389}
1390
1391/*
1392** Re-entrant version of localtime.
1393*/
1394
1395struct tm *
1396localtime_r(timep, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001397const time_t * const timep;
1398struct tm * tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001399{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001400 struct tm* result;
1401
1402 _tzLock();
1403 tzset_locked();
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001404 result = localsub(timep, 0L, tmp);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001405 _tzUnlock();
1406
1407 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001408}
1409
1410/*
1411** gmtsub is to gmtime as localsub is to localtime.
1412*/
1413
1414static struct tm *
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001415gmtsub(timep, offset, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001416const time_t * const timep;
1417const long offset;
1418struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001419{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001420 register struct tm * result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001421
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001422 if (!gmt_is_set) {
1423 gmt_is_set = TRUE;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001424#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001425 gmtptr = (struct state *) malloc(sizeof *gmtptr);
1426 if (gmtptr != NULL)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001427#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001428 gmtload(gmtptr);
1429 }
1430 result = timesub(timep, offset, gmtptr, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001431#ifdef TM_ZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001432 /*
1433 ** Could get fancy here and deliver something such as
1434 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
1435 ** but this is no time for a treasure hunt.
1436 */
1437 if (offset != 0)
1438 tmp->TM_ZONE = wildabbr;
1439 else {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001440#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001441 if (gmtptr == NULL)
1442 tmp->TM_ZONE = gmt;
1443 else tmp->TM_ZONE = gmtptr->chars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001444#endif /* defined ALL_STATE */
1445#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001446 tmp->TM_ZONE = gmtptr->chars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001447#endif /* State Farm */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001448 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001449#endif /* defined TM_ZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001450 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001451}
1452
1453struct tm *
1454gmtime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001455const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001456{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001457 return gmtime_r(timep, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001458}
1459
1460/*
1461* Re-entrant version of gmtime.
1462*/
1463
1464struct tm *
1465gmtime_r(timep, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001466const time_t * const timep;
1467struct tm * tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001468{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001469 struct tm* result;
1470
1471 _tzLock();
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001472 result = gmtsub(timep, 0L, tmp);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001473 _tzUnlock();
1474
1475 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001476}
1477
1478#ifdef STD_INSPIRED
David 'Digit' Turner6481b912010-12-06 12:23:16 +01001479#if 0 /* disabled because there is no good documentation for this function */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001480struct tm *
1481offtime(timep, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001482const time_t * const timep;
1483const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001484{
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001485 return gmtsub(timep, offset, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001486}
David 'Digit' Turner6481b912010-12-06 12:23:16 +01001487#endif /* 0 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001488#endif /* defined STD_INSPIRED */
1489
1490/*
1491** Return the number of leap years through the end of the given year
1492** where, to make the math easy, the answer for year zero is defined as zero.
1493*/
1494
1495static int
1496leaps_thru_end_of(y)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001497register const int y;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001498{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001499 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1500 -(leaps_thru_end_of(-(y + 1)) + 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001501}
1502
1503static struct tm *
1504timesub(timep, offset, sp, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001505const time_t * const timep;
1506const long offset;
1507register const struct state * const sp;
1508register struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001509{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001510 register const struct lsinfo * lp;
1511 register time_t tdays;
1512 register int idays; /* unsigned would be so 2003 */
1513 register long rem;
1514 int y;
1515 register const int * ip;
1516 register long corr;
1517 register int hit;
1518 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001519
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001520 corr = 0;
1521 hit = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001522#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001523 i = (sp == NULL) ? 0 : sp->leapcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001524#endif /* defined ALL_STATE */
1525#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001526 i = sp->leapcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001527#endif /* State Farm */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001528 while (--i >= 0) {
1529 lp = &sp->lsis[i];
1530 if (*timep >= lp->ls_trans) {
1531 if (*timep == lp->ls_trans) {
1532 hit = ((i == 0 && lp->ls_corr > 0) ||
1533 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1534 if (hit)
1535 while (i > 0 &&
1536 sp->lsis[i].ls_trans ==
1537 sp->lsis[i - 1].ls_trans + 1 &&
1538 sp->lsis[i].ls_corr ==
1539 sp->lsis[i - 1].ls_corr + 1) {
1540 ++hit;
1541 --i;
1542 }
1543 }
1544 corr = lp->ls_corr;
1545 break;
1546 }
1547 }
1548 y = EPOCH_YEAR;
1549 tdays = *timep / SECSPERDAY;
1550 rem = *timep - tdays * SECSPERDAY;
1551 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1552 int newy;
1553 register time_t tdelta;
1554 register int idelta;
1555 register int leapdays;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001556
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001557 tdelta = tdays / DAYSPERLYEAR;
1558 idelta = tdelta;
1559 if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
1560 return NULL;
1561 if (idelta == 0)
1562 idelta = (tdays < 0) ? -1 : 1;
1563 newy = y;
1564 if (increment_overflow(&newy, idelta))
1565 return NULL;
1566 leapdays = leaps_thru_end_of(newy - 1) -
1567 leaps_thru_end_of(y - 1);
1568 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1569 tdays -= leapdays;
1570 y = newy;
1571 }
1572 {
1573 register long seconds;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001574
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001575 seconds = tdays * SECSPERDAY + 0.5;
1576 tdays = seconds / SECSPERDAY;
1577 rem += seconds - tdays * SECSPERDAY;
1578 }
1579 /*
1580 ** Given the range, we can now fearlessly cast...
1581 */
1582 idays = tdays;
1583 rem += offset - corr;
1584 while (rem < 0) {
1585 rem += SECSPERDAY;
1586 --idays;
1587 }
1588 while (rem >= SECSPERDAY) {
1589 rem -= SECSPERDAY;
1590 ++idays;
1591 }
1592 while (idays < 0) {
1593 if (increment_overflow(&y, -1))
1594 return NULL;
1595 idays += year_lengths[isleap(y)];
1596 }
1597 while (idays >= year_lengths[isleap(y)]) {
1598 idays -= year_lengths[isleap(y)];
1599 if (increment_overflow(&y, 1))
1600 return NULL;
1601 }
1602 tmp->tm_year = y;
1603 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1604 return NULL;
1605 tmp->tm_yday = idays;
1606 /*
1607 ** The "extra" mods below avoid overflow problems.
1608 */
1609 tmp->tm_wday = EPOCH_WDAY +
1610 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
1611 (DAYSPERNYEAR % DAYSPERWEEK) +
1612 leaps_thru_end_of(y - 1) -
1613 leaps_thru_end_of(EPOCH_YEAR - 1) +
1614 idays;
1615 tmp->tm_wday %= DAYSPERWEEK;
1616 if (tmp->tm_wday < 0)
1617 tmp->tm_wday += DAYSPERWEEK;
1618 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1619 rem %= SECSPERHOUR;
1620 tmp->tm_min = (int) (rem / SECSPERMIN);
1621 /*
1622 ** A positive leap second requires a special
1623 ** representation. This uses "... ??:59:60" et seq.
1624 */
1625 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1626 ip = mon_lengths[isleap(y)];
1627 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1628 idays -= ip[tmp->tm_mon];
1629 tmp->tm_mday = (int) (idays + 1);
1630 tmp->tm_isdst = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001631#ifdef TM_GMTOFF
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001632 tmp->TM_GMTOFF = offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001633#endif /* defined TM_GMTOFF */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001634 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001635}
1636
1637char *
1638ctime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001639const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001640{
1641/*
1642** Section 4.12.3.2 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001643** The ctime function converts the calendar time pointed to by timer
1644** to local time in the form of a string. It is equivalent to
1645** asctime(localtime(timer))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001646*/
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001647 return asctime(localtime(timep));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001648}
1649
1650char *
1651ctime_r(timep, buf)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001652const time_t * const timep;
1653char * buf;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001654{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001655 struct tm mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001656
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001657 return asctime_r(localtime_r(timep, &mytm), buf);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001658}
1659
1660/*
1661** Adapted from code provided by Robert Elz, who writes:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001662** The "best" way to do mktime I think is based on an idea of Bob
1663** Kridle's (so its said...) from a long time ago.
1664** It does a binary search of the time_t space. Since time_t's are
1665** just 32 bits, its a max of 32 iterations (even at 64 bits it
1666** would still be very reasonable).
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001667*/
1668
1669#ifndef WRONG
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001670#define WRONG (-1)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001671#endif /* !defined WRONG */
1672
1673/*
1674** Simplified normalize logic courtesy Paul Eggert.
1675*/
1676
1677static int
1678increment_overflow(number, delta)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001679int * number;
1680int delta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001681{
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001682 unsigned number0 = (unsigned)*number;
1683 unsigned number1 = (unsigned)(number0 + delta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001684
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001685 *number = (int)number1;
1686
1687 if (delta >= 0) {
1688 return ((int)number1 < (int)number0);
1689 } else {
1690 return ((int)number1 > (int)number0);
1691 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001692}
1693
1694static int
1695long_increment_overflow(number, delta)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001696long * number;
1697int delta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001698{
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001699 unsigned long number0 = (unsigned long)*number;
1700 unsigned long number1 = (unsigned long)(number0 + delta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001701
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001702 *number = (long)number1;
1703
1704 if (delta >= 0) {
1705 return ((long)number1 < (long)number0);
1706 } else {
1707 return ((long)number1 > (long)number0);
1708 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001709}
1710
1711static int
1712normalize_overflow(tensptr, unitsptr, base)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001713int * const tensptr;
1714int * const unitsptr;
1715const int base;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001716{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001717 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001718
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001719 tensdelta = (*unitsptr >= 0) ?
1720 (*unitsptr / base) :
1721 (-1 - (-1 - *unitsptr) / base);
1722 *unitsptr -= tensdelta * base;
1723 return increment_overflow(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001724}
1725
1726static int
1727long_normalize_overflow(tensptr, unitsptr, base)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001728long * const tensptr;
1729int * const unitsptr;
1730const int base;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001731{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001732 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001733
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001734 tensdelta = (*unitsptr >= 0) ?
1735 (*unitsptr / base) :
1736 (-1 - (-1 - *unitsptr) / base);
1737 *unitsptr -= tensdelta * base;
1738 return long_increment_overflow(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001739}
1740
1741static int
1742tmcomp(atmp, btmp)
1743register const struct tm * const atmp;
1744register const struct tm * const btmp;
1745{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001746 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001747
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001748 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1749 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1750 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1751 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1752 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1753 result = atmp->tm_sec - btmp->tm_sec;
1754 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001755}
1756
1757static time_t
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001758time2sub(tmp, funcp, offset, okayp, do_norm_secs)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001759struct tm * const tmp;
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001760struct tm * (* const funcp) P((const time_t*, long, struct tm*));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001761const long offset;
1762int * const okayp;
1763const int do_norm_secs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001764{
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001765 register const struct state * sp;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001766 register int dir;
1767 register int i, j;
1768 register int saved_seconds;
1769 register long li;
1770 register time_t lo;
1771 register time_t hi;
1772 long y;
1773 time_t newt;
1774 time_t t;
1775 struct tm yourtm, mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001776
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001777 *okayp = FALSE;
1778 yourtm = *tmp;
1779 if (do_norm_secs) {
1780 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1781 SECSPERMIN))
1782 return WRONG;
1783 }
1784 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1785 return WRONG;
1786 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1787 return WRONG;
1788 y = yourtm.tm_year;
1789 if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
1790 return WRONG;
1791 /*
1792 ** Turn y into an actual year number for now.
1793 ** It is converted back to an offset from TM_YEAR_BASE later.
1794 */
1795 if (long_increment_overflow(&y, TM_YEAR_BASE))
1796 return WRONG;
1797 while (yourtm.tm_mday <= 0) {
1798 if (long_increment_overflow(&y, -1))
1799 return WRONG;
1800 li = y + (1 < yourtm.tm_mon);
1801 yourtm.tm_mday += year_lengths[isleap(li)];
1802 }
1803 while (yourtm.tm_mday > DAYSPERLYEAR) {
1804 li = y + (1 < yourtm.tm_mon);
1805 yourtm.tm_mday -= year_lengths[isleap(li)];
1806 if (long_increment_overflow(&y, 1))
1807 return WRONG;
1808 }
1809 for ( ; ; ) {
1810 i = mon_lengths[isleap(y)][yourtm.tm_mon];
1811 if (yourtm.tm_mday <= i)
1812 break;
1813 yourtm.tm_mday -= i;
1814 if (++yourtm.tm_mon >= MONSPERYEAR) {
1815 yourtm.tm_mon = 0;
1816 if (long_increment_overflow(&y, 1))
1817 return WRONG;
1818 }
1819 }
1820 if (long_increment_overflow(&y, -TM_YEAR_BASE))
1821 return WRONG;
1822 yourtm.tm_year = y;
1823 if (yourtm.tm_year != y)
1824 return WRONG;
1825 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
1826 saved_seconds = 0;
1827 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
1828 /*
1829 ** We can't set tm_sec to 0, because that might push the
1830 ** time below the minimum representable time.
1831 ** Set tm_sec to 59 instead.
1832 ** This assumes that the minimum representable time is
1833 ** not in the same minute that a leap second was deleted from,
1834 ** which is a safer assumption than using 58 would be.
1835 */
1836 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1837 return WRONG;
1838 saved_seconds = yourtm.tm_sec;
1839 yourtm.tm_sec = SECSPERMIN - 1;
1840 } else {
1841 saved_seconds = yourtm.tm_sec;
1842 yourtm.tm_sec = 0;
1843 }
1844 /*
1845 ** Do a binary search (this works whatever time_t's type is).
1846 */
1847 if (!TYPE_SIGNED(time_t)) {
1848 lo = 0;
1849 hi = lo - 1;
1850 } else if (!TYPE_INTEGRAL(time_t)) {
1851 if (sizeof(time_t) > sizeof(float))
1852 hi = (time_t) DBL_MAX;
1853 else hi = (time_t) FLT_MAX;
1854 lo = -hi;
1855 } else {
1856 lo = 1;
1857 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
1858 lo *= 2;
1859 hi = -(lo + 1);
1860 }
1861 for ( ; ; ) {
1862 t = lo / 2 + hi / 2;
1863 if (t < lo)
1864 t = lo;
1865 else if (t > hi)
1866 t = hi;
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001867 if ((*funcp)(&t, offset, &mytm) == NULL) {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001868 /*
1869 ** Assume that t is too extreme to be represented in
1870 ** a struct tm; arrange things so that it is less
1871 ** extreme on the next pass.
1872 */
1873 dir = (t > 0) ? 1 : -1;
1874 } else dir = tmcomp(&mytm, &yourtm);
1875 if (dir != 0) {
1876 if (t == lo) {
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001877 if (t == TIME_T_MAX)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001878 return WRONG;
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001879 ++t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001880 ++lo;
1881 } else if (t == hi) {
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001882 if (t == TIME_T_MIN)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001883 return WRONG;
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001884 --t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001885 --hi;
1886 }
1887 if (lo > hi)
1888 return WRONG;
1889 if (dir > 0)
1890 hi = t;
1891 else lo = t;
1892 continue;
1893 }
1894 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1895 break;
1896 /*
1897 ** Right time, wrong type.
1898 ** Hunt for right time, right type.
1899 ** It's okay to guess wrong since the guess
1900 ** gets checked.
1901 */
1902 /*
1903 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1904 */
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001905 sp = (const struct state *)
1906 (((void *) funcp == (void *) localsub) ?
1907 lclptr : gmtptr);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001908#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001909 if (sp == NULL)
1910 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001911#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001912 for (i = sp->typecnt - 1; i >= 0; --i) {
1913 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1914 continue;
1915 for (j = sp->typecnt - 1; j >= 0; --j) {
1916 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1917 continue;
1918 newt = t + sp->ttis[j].tt_gmtoff -
1919 sp->ttis[i].tt_gmtoff;
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001920 if ((*funcp)(&newt, offset, &mytm) == NULL)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001921 continue;
1922 if (tmcomp(&mytm, &yourtm) != 0)
1923 continue;
1924 if (mytm.tm_isdst != yourtm.tm_isdst)
1925 continue;
1926 /*
1927 ** We have a match.
1928 */
1929 t = newt;
1930 goto label;
1931 }
1932 }
1933 return WRONG;
1934 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001935label:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001936 newt = t + saved_seconds;
1937 if ((newt < t) != (saved_seconds < 0))
1938 return WRONG;
1939 t = newt;
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001940 if ((*funcp)(&t, offset, tmp))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001941 *okayp = TRUE;
1942 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001943}
1944
1945static time_t
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001946time2(tmp, funcp, offset, okayp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001947struct tm * const tmp;
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001948struct tm * (* const funcp) P((const time_t*, long, struct tm*));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001949const long offset;
1950int * const okayp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001951{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001952 time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001953
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001954 /*
1955 ** First try without normalization of seconds
1956 ** (in case tm_sec contains a value associated with a leap second).
1957 ** If that fails, try with normalization of seconds.
1958 */
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001959 t = time2sub(tmp, funcp, offset, okayp, FALSE);
1960 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001961}
1962
1963static time_t
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001964time1(tmp, funcp, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001965struct tm * const tmp;
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001966struct tm * (* const funcp) P((const time_t *, long, struct tm *));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001967const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001968{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001969 register time_t t;
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001970 register const struct state * sp;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001971 register int samei, otheri;
1972 register int sameind, otherind;
1973 register int i;
1974 register int nseen;
1975 int seen[TZ_MAX_TYPES];
1976 int types[TZ_MAX_TYPES];
1977 int okay;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001978
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001979 if (tmp->tm_isdst > 1)
1980 tmp->tm_isdst = 1;
Elliott Hughesf4b34b62012-09-24 10:13:12 -07001981 t = time2(tmp, funcp, offset, &okay);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001982#ifdef PCTS
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001983 /*
1984 ** PCTS code courtesy Grant Sullivan.
1985 */
1986 if (okay)
1987 return t;
1988 if (tmp->tm_isdst < 0)
1989 tmp->tm_isdst = 0; /* reset to std and try again */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001990#endif /* defined PCTS */
1991#ifndef PCTS
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001992 if (okay || tmp->tm_isdst < 0)
1993 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001994#endif /* !defined PCTS */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001995 /*
1996 ** We're supposed to assume that somebody took a time of one type
1997 ** and did some math on it that yielded a "struct tm" that's bad.
1998 ** We try to divine the type they started from and adjust to the
1999 ** type they need.
2000 */
2001 /*
2002 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
2003 */
Elliott Hughesf4b34b62012-09-24 10:13:12 -07002004 sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
2005 lclptr : gmtptr);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002006#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002007 if (sp == NULL)
2008 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002009#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002010 for (i = 0; i < sp->typecnt; ++i)
2011 seen[i] = FALSE;
2012 nseen = 0;
2013 for (i = sp->timecnt - 1; i >= 0; --i)
2014 if (!seen[sp->types[i]]) {
2015 seen[sp->types[i]] = TRUE;
2016 types[nseen++] = sp->types[i];
2017 }
2018 for (sameind = 0; sameind < nseen; ++sameind) {
2019 samei = types[sameind];
2020 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2021 continue;
2022 for (otherind = 0; otherind < nseen; ++otherind) {
2023 otheri = types[otherind];
2024 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2025 continue;
2026 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
2027 sp->ttis[samei].tt_gmtoff;
2028 tmp->tm_isdst = !tmp->tm_isdst;
Elliott Hughesf4b34b62012-09-24 10:13:12 -07002029 t = time2(tmp, funcp, offset, &okay);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002030 if (okay)
2031 return t;
2032 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
2033 sp->ttis[samei].tt_gmtoff;
2034 tmp->tm_isdst = !tmp->tm_isdst;
2035 }
2036 }
2037 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002038}
2039
2040time_t
2041mktime(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002042struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002043{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002044 time_t result;
2045 _tzLock();
2046 tzset_locked();
Elliott Hughesf4b34b62012-09-24 10:13:12 -07002047 result = time1(tmp, localsub, 0L);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002048 _tzUnlock();
2049 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002050}
2051
2052#ifdef STD_INSPIRED
2053
2054time_t
2055timelocal(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002056struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002057{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002058 tmp->tm_isdst = -1; /* in case it wasn't initialized */
2059 return mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002060}
2061
2062time_t
2063timegm(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002064struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002065{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002066 time_t result;
2067
2068 tmp->tm_isdst = 0;
2069 _tzLock();
Elliott Hughesf4b34b62012-09-24 10:13:12 -07002070 result = time1(tmp, gmtsub, 0L);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002071 _tzUnlock();
2072
2073 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002074}
2075
David 'Digit' Turner6481b912010-12-06 12:23:16 +01002076#if 0 /* disable due to lack of clear documentation on this function */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002077time_t
2078timeoff(tmp, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002079struct tm * const tmp;
2080const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002081{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002082 time_t result;
2083
2084 tmp->tm_isdst = 0;
2085 _tzLock();
Elliott Hughesf4b34b62012-09-24 10:13:12 -07002086 result = time1(tmp, gmtsub, offset);
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002087 _tzUnlock();
2088
2089 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002090}
David 'Digit' Turner6481b912010-12-06 12:23:16 +01002091#endif /* 0 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002092
2093#endif /* defined STD_INSPIRED */
2094
2095#ifdef CMUCS
2096
2097/*
2098** The following is supplied for compatibility with
2099** previous versions of the CMUCS runtime library.
2100*/
2101
2102long
2103gtime(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002104struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002105{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002106 const time_t t = mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002107
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002108 if (t == WRONG)
2109 return -1;
2110 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002111}
2112
2113#endif /* defined CMUCS */
2114
2115/*
2116** XXX--is the below the right way to conditionalize??
2117*/
2118
2119#ifdef STD_INSPIRED
2120
2121/*
2122** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2123** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2124** is not the case if we are accounting for leap seconds.
2125** So, we provide the following conversion routines for use
2126** when exchanging timestamps with POSIX conforming systems.
2127*/
2128
2129static long
2130leapcorr(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002131time_t * timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002132{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002133 register struct state * sp;
2134 register struct lsinfo * lp;
2135 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002136
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002137 sp = lclptr;
2138 i = sp->leapcnt;
2139 while (--i >= 0) {
2140 lp = &sp->lsis[i];
2141 if (*timep >= lp->ls_trans)
2142 return lp->ls_corr;
2143 }
2144 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002145}
2146
2147time_t
2148time2posix(t)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002149time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002150{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002151 tzset();
2152 return t - leapcorr(&t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002153}
2154
2155time_t
2156posix2time(t)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002157time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002158{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002159 time_t x;
2160 time_t y;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002161
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002162 tzset();
2163 /*
2164 ** For a positive leap second hit, the result
2165 ** is not unique. For a negative leap second
2166 ** hit, the corresponding time doesn't exist,
2167 ** so we return an adjacent second.
2168 */
2169 x = t + leapcorr(&t);
2170 y = x - leapcorr(&x);
2171 if (y < t) {
2172 do {
2173 x++;
2174 y = x - leapcorr(&x);
2175 } while (y < t);
2176 if (t != y)
2177 return x - 1;
2178 } else if (y > t) {
2179 do {
2180 --x;
2181 y = x - leapcorr(&x);
2182 } while (y > t);
2183 if (t != y)
2184 return x + 1;
2185 }
2186 return x;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002187}
2188
2189#endif /* defined STD_INSPIRED */
Elliott Hughesd23af232012-10-17 16:30:47 -07002190
Elliott Hughes1c295722012-10-19 18:13:15 -07002191#include <assert.h>
Elliott Hughesd23af232012-10-17 16:30:47 -07002192#include <stdint.h>
Elliott Hughes8b954042012-10-18 13:42:59 -07002193#include <arpa/inet.h> // For ntohl(3).
Elliott Hughesd23af232012-10-17 16:30:47 -07002194
Elliott Hughes1c295722012-10-19 18:13:15 -07002195static int __bionic_open_tzdata_path(const char* path, const char* olson_id, int* data_size) {
2196 int fd = TEMP_FAILURE_RETRY(open(path, OPEN_MODE));
Elliott Hughesd23af232012-10-17 16:30:47 -07002197 if (fd == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002198 XLOG(("%s: could not open \"%s\": %s\n", __FUNCTION__, path, strerror(errno)));
2199 return -2; // Distinguish failure to find any data from failure to find a specific id.
Elliott Hughesd23af232012-10-17 16:30:47 -07002200 }
2201
2202 // byte[12] tzdata_version -- "tzdata2012f\0"
Elliott Hughesd23af232012-10-17 16:30:47 -07002203 // int index_offset
2204 // int data_offset
2205 // int zonetab_offset
2206 struct bionic_tzdata_header {
2207 char tzdata_version[12];
Elliott Hughesd23af232012-10-17 16:30:47 -07002208 int32_t index_offset;
2209 int32_t data_offset;
2210 int32_t zonetab_offset;
2211 } header;
2212 if (TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header))) != sizeof(header)) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002213 fprintf(stderr, "%s: could not read header: %s\n", __FUNCTION__, strerror(errno));
Elliott Hughesd23af232012-10-17 16:30:47 -07002214 close(fd);
2215 return -1;
2216 }
2217
2218 if (strncmp(header.tzdata_version, "tzdata", 6) != 0 || header.tzdata_version[11] != 0) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002219 fprintf(stderr, "%s: bad magic: %s\n", __FUNCTION__, header.tzdata_version);
Elliott Hughesd23af232012-10-17 16:30:47 -07002220 close(fd);
2221 return -1;
2222 }
Elliott Hughesd23af232012-10-17 16:30:47 -07002223
2224#if 0
Elliott Hughes23935352012-10-22 14:47:58 -07002225 fprintf(stderr, "version: %s\n", header.tzdata_version);
Elliott Hughesd23af232012-10-17 16:30:47 -07002226 fprintf(stderr, "index_offset = %d\n", ntohl(header.index_offset));
2227 fprintf(stderr, "data_offset = %d\n", ntohl(header.data_offset));
2228 fprintf(stderr, "zonetab_offset = %d\n", ntohl(header.zonetab_offset));
2229#endif
2230
2231 if (TEMP_FAILURE_RETRY(lseek(fd, ntohl(header.index_offset), SEEK_SET)) == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002232 fprintf(stderr, "%s: couldn't seek to index: %s\n", __FUNCTION__, strerror(errno));
Elliott Hughesd23af232012-10-17 16:30:47 -07002233 close(fd);
2234 return -1;
2235 }
2236
2237 off_t specific_zone_offset = -1;
2238
Elliott Hughes1c295722012-10-19 18:13:15 -07002239 static const size_t NAME_LENGTH = 40;
2240 unsigned char buf[NAME_LENGTH + 3 * sizeof(int32_t)];
2241 while (TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf))) == (ssize_t) sizeof(buf)) {
2242 char this_id[NAME_LENGTH + 1];
2243 memcpy(this_id, buf, NAME_LENGTH);
2244 this_id[NAME_LENGTH] = '\0';
Elliott Hughesd23af232012-10-17 16:30:47 -07002245
2246 if (strcmp(this_id, olson_id) == 0) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002247 specific_zone_offset = toint(buf + NAME_LENGTH) + ntohl(header.data_offset);
2248 *data_size = toint(buf + NAME_LENGTH + sizeof(int32_t));
Elliott Hughesd23af232012-10-17 16:30:47 -07002249 break;
2250 }
2251 }
2252
2253 if (specific_zone_offset == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002254 XLOG(("%s: couldn't find zone \"%s\"\n", __FUNCTION__, olson_id));
Elliott Hughesd23af232012-10-17 16:30:47 -07002255 close(fd);
2256 return -1;
2257 }
2258
2259 if (TEMP_FAILURE_RETRY(lseek(fd, specific_zone_offset, SEEK_SET)) == -1) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002260 fprintf(stderr, "%s: could not seek to %ld: %s\n", __FUNCTION__, specific_zone_offset, strerror(errno));
Elliott Hughesd23af232012-10-17 16:30:47 -07002261 close(fd);
2262 return -1;
2263 }
2264
2265 return fd;
2266}
Elliott Hughes1c295722012-10-19 18:13:15 -07002267
2268static int __bionic_open_tzdata(const char* olson_id, int* data_size) {
2269 // TODO: use $ANDROID_DATA and $ANDROID_ROOT like libcore, to support bionic on the host.
2270 int fd = __bionic_open_tzdata_path("/data/misc/zoneinfo/tzdata", olson_id, data_size);
2271 if (fd < 0) {
2272 fd = __bionic_open_tzdata_path("/system/usr/share/zoneinfo/tzdata", olson_id, data_size);
2273 if (fd == -2) {
Elliott Hughes49271d82012-10-25 14:38:51 -07002274 // The first thing that 'recovery' does is try to format the current time. It doesn't have
2275 // any tzdata available, so we must not abort here --- doing so breaks the recovery image!
2276 fprintf(stderr, "%s: couldn't find any tzdata when looking for %s!\n", __FUNCTION__, olson_id);
Elliott Hughes1c295722012-10-19 18:13:15 -07002277 }
2278 }
2279 return fd;
2280}