blob: 83c101162fe5315ceb2e7da4e803f2c84f202d66 [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
40#define INDEXFILE "/system/usr/share/zoneinfo/zoneinfo.idx"
41#define DATAFILE "/system/usr/share/zoneinfo/zoneinfo.dat"
42#define NAMELEN 40
43#define INTLEN 4
44#define READLEN (NAMELEN + 3 * INTLEN)
45
46/*
47** SunOS 4.1.1 headers lack O_BINARY.
48*/
49
50#ifdef O_BINARY
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070051#define OPEN_MODE (O_RDONLY | O_BINARY)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080052#endif /* defined O_BINARY */
53#ifndef O_BINARY
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070054#define OPEN_MODE O_RDONLY
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080055#endif /* !defined O_BINARY */
56
57#if 0
58# define XLOG(xx) printf xx , fflush(stdout)
59#else
60# define XLOG(x) do{}while (0)
61#endif
62
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070063/* THREAD-SAFETY SUPPORT GOES HERE */
64static pthread_mutex_t _tzMutex = PTHREAD_MUTEX_INITIALIZER;
65
66static __inline__ void _tzLock(void)
67{
68 if (__isthreaded)
69 pthread_mutex_lock(&_tzMutex);
70}
71
72static __inline__ void _tzUnlock(void)
73{
74 if (__isthreaded)
75 pthread_mutex_unlock(&_tzMutex);
76}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080077
David 'Digit' Turner2093d352009-09-09 17:41:59 -070078/* Complex computations to determine the min/max of time_t depending
79 * on TYPE_BIT / TYPE_SIGNED / TYPE_INTEGRAL.
80 * These macros cannot be used in pre-processor directives, so we
81 * let the C compiler do the work, which makes things a bit funky.
82 */
83static const time_t TIME_T_MAX =
84 TYPE_INTEGRAL(time_t) ?
85 ( TYPE_SIGNED(time_t) ?
86 ~((time_t)1 << (TYPE_BIT(time_t)-1))
87 :
88 ~(time_t)0
89 )
90 : /* if time_t is a floating point number */
91 ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MAX : (time_t)FLT_MAX );
92
93static const time_t TIME_T_MIN =
94 TYPE_INTEGRAL(time_t) ?
95 ( TYPE_SIGNED(time_t) ?
96 ((time_t)1 << (TYPE_BIT(time_t)-1))
97 :
98 0
99 )
100 :
101 ( sizeof(time_t) > sizeof(float) ? (time_t)DBL_MIN : (time_t)FLT_MIN );
102
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800103#ifndef WILDABBR
104/*
105** Someone might make incorrect use of a time zone abbreviation:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700106** 1. They might reference tzname[0] before calling tzset (explicitly
107** or implicitly).
108** 2. They might reference tzname[1] before calling tzset (explicitly
109** or implicitly).
110** 3. They might reference tzname[1] after setting to a time zone
111** in which Daylight Saving Time is never observed.
112** 4. They might reference tzname[0] after setting to a time zone
113** in which Standard Time is never observed.
114** 5. They might reference tm.TM_ZONE after calling offtime.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800115** What's best to do in the above cases is open to debate;
116** for now, we just set things up so that in any of the five cases
117** WILDABBR is used. Another possibility: initialize tzname[0] to the
118** string "tzname[0] used before set", and similarly for the other cases.
119** And another: initialize tzname[0] to "ERA", with an explanation in the
120** manual page of what this "time zone abbreviation" means (doing this so
121** that tzname[0] has the "normal" length of three characters).
122*/
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700123#define WILDABBR " "
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800124#endif /* !defined WILDABBR */
125
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700126static char wildabbr[] = WILDABBR;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800127
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700128static const char gmt[] = "GMT";
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800129
130/*
131** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
132** We default to US rules as of 1999-08-17.
133** POSIX 1003.1 section 8.1.1 says that the default DST rules are
134** implementation dependent; for historical reasons, US rules are a
135** common default.
136*/
137#ifndef TZDEFRULESTRING
138#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
139#endif /* !defined TZDEFDST */
140
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700141struct ttinfo { /* time type information */
142 long tt_gmtoff; /* UTC offset in seconds */
143 int tt_isdst; /* used to set tm_isdst */
144 int tt_abbrind; /* abbreviation list index */
145 int tt_ttisstd; /* TRUE if transition is std time */
146 int tt_ttisgmt; /* TRUE if transition is UTC */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800147};
148
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700149struct lsinfo { /* leap second information */
150 time_t ls_trans; /* transition time */
151 long ls_corr; /* correction to apply */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800152};
153
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700154#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800155
156#ifdef TZNAME_MAX
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700157#define MY_TZNAME_MAX TZNAME_MAX
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800158#endif /* defined TZNAME_MAX */
159#ifndef TZNAME_MAX
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700160#define MY_TZNAME_MAX 255
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800161#endif /* !defined TZNAME_MAX */
162
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700163/* XXX: This code should really use time64_t instead of time_t
164 * but we can't change it without re-generating the index
165 * file first with the correct data.
166 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800167struct state {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700168 int leapcnt;
169 int timecnt;
170 int typecnt;
171 int charcnt;
172 int goback;
173 int goahead;
174 time_t ats[TZ_MAX_TIMES];
175 unsigned char types[TZ_MAX_TIMES];
176 struct ttinfo ttis[TZ_MAX_TYPES];
177 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
178 (2 * (MY_TZNAME_MAX + 1)))];
179 struct lsinfo lsis[TZ_MAX_LEAPS];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800180};
181
182struct rule {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700183 int r_type; /* type of rule--see below */
184 int r_day; /* day number of rule */
185 int r_week; /* week number of rule */
186 int r_mon; /* month number of rule */
187 long r_time; /* transition time of rule */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800188};
189
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700190#define JULIAN_DAY 0 /* Jn - Julian day */
191#define DAY_OF_YEAR 1 /* n - day of year */
192#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 -0800193
194/*
195** Prototypes for static functions.
196*/
197
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700198/* NOTE: all internal functions assume that _tzLock() was already called */
199
200static long detzcode P((const char * codep));
201static time_t detzcode64 P((const char * codep));
202static int differ_by_repeat P((time_t t1, time_t t0));
203static const char * getzname P((const char * strp));
204static const char * getqzname P((const char * strp, const int delim));
205static const char * getnum P((const char * strp, int * nump, int min,
206 int max));
207static const char * getsecs P((const char * strp, long * secsp));
208static const char * getoffset P((const char * strp, long * offsetp));
209static const char * getrule P((const char * strp, struct rule * rulep));
210static void gmtload P((struct state * sp));
211static struct tm * gmtsub P((const time_t * timep, long offset,
212 struct tm * tmp));
213static struct tm * localsub P((const time_t * timep, long offset,
214 struct tm * tmp));
215static int increment_overflow P((int * number, int delta));
216static int leaps_thru_end_of P((int y));
217static int long_increment_overflow P((long * number, int delta));
218static int long_normalize_overflow P((long * tensptr,
219 int * unitsptr, int base));
220static int normalize_overflow P((int * tensptr, int * unitsptr,
221 int base));
222static void settzname P((void));
223static time_t time1 P((struct tm * tmp,
224 struct tm * (*funcp) P((const time_t *,
225 long, struct tm *)),
226 long offset));
227static time_t time2 P((struct tm *tmp,
228 struct tm * (*funcp) P((const time_t *,
229 long, struct tm*)),
230 long offset, int * okayp));
231static time_t time2sub P((struct tm *tmp,
232 struct tm * (*funcp) P((const time_t *,
233 long, struct tm*)),
234 long offset, int * okayp, int do_norm_secs));
235static struct tm * timesub P((const time_t * timep, long offset,
236 const struct state * sp, struct tm * tmp));
237static int tmcomp P((const struct tm * atmp,
238 const struct tm * btmp));
239static time_t transtime P((time_t janfirst, int year,
240 const struct rule * rulep, long offset));
241static int tzload P((const char * name, struct state * sp,
242 int doextend));
243static int tzparse P((const char * name, struct state * sp,
244 int lastditch));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800245
246#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700247static struct state * lclptr;
248static struct state * gmtptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800249#endif /* defined ALL_STATE */
250
251#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700252static struct state lclmem;
253static struct state gmtmem;
254#define lclptr (&lclmem)
255#define gmtptr (&gmtmem)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800256#endif /* State Farm */
257
258#ifndef TZ_STRLEN_MAX
259#define TZ_STRLEN_MAX 255
260#endif /* !defined TZ_STRLEN_MAX */
261
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700262static char lcl_TZname[TZ_STRLEN_MAX + 1];
263static int lcl_is_set;
264static int gmt_is_set;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800265
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700266char * tzname[2] = {
267 wildabbr,
268 wildabbr
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800269};
270
271/*
272** Section 4.12.3 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700273** Except for the strftime function, these functions [asctime,
274** ctime, gmtime, localtime] return values in one of two static
275** objects: a broken-down time structure and an array of char.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800276** Thanks to Paul Eggert for noting this.
277*/
278
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700279static struct tm tmGlobal;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800280
281#ifdef USG_COMPAT
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700282time_t timezone = 0;
283int daylight = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800284#endif /* defined USG_COMPAT */
285
286#ifdef ALTZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700287time_t altzone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800288#endif /* defined ALTZONE */
289
290static long
291detzcode(codep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700292const char * const codep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800293{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700294 register long result;
295 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800296
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700297 result = (codep[0] & 0x80) ? ~0L : 0;
298 for (i = 0; i < 4; ++i)
299 result = (result << 8) | (codep[i] & 0xff);
300 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800301}
302
303static time_t
304detzcode64(codep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700305const char * const codep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800306{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700307 register time_t result;
308 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800309
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700310 result = (codep[0] & 0x80) ? (~(int_fast64_t) 0) : 0;
311 for (i = 0; i < 8; ++i)
312 result = result * 256 + (codep[i] & 0xff);
313 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800314}
315
316static void
317settzname P((void))
318{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700319 register struct state * const sp = lclptr;
320 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800321
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700322 tzname[0] = wildabbr;
323 tzname[1] = wildabbr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800324#ifdef USG_COMPAT
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700325 daylight = 0;
326 timezone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800327#endif /* defined USG_COMPAT */
328#ifdef ALTZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700329 altzone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800330#endif /* defined ALTZONE */
331#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700332 if (sp == NULL) {
333 tzname[0] = tzname[1] = gmt;
334 return;
335 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800336#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700337 for (i = 0; i < sp->typecnt; ++i) {
338 register const struct ttinfo * const ttisp = &sp->ttis[i];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800339
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700340 tzname[ttisp->tt_isdst] =
341 &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800342#ifdef USG_COMPAT
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700343 if (ttisp->tt_isdst)
344 daylight = 1;
345 if (i == 0 || !ttisp->tt_isdst)
346 timezone = -(ttisp->tt_gmtoff);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800347#endif /* defined USG_COMPAT */
348#ifdef ALTZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700349 if (i == 0 || ttisp->tt_isdst)
350 altzone = -(ttisp->tt_gmtoff);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800351#endif /* defined ALTZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700352 }
353 /*
354 ** And to get the latest zone names into tzname. . .
355 */
356 for (i = 0; i < sp->timecnt; ++i) {
357 register const struct ttinfo * const ttisp =
358 &sp->ttis[
359 sp->types[i]];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800360
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700361 tzname[ttisp->tt_isdst] =
362 &sp->chars[ttisp->tt_abbrind];
363 }
364 /*
365 ** Finally, scrub the abbreviations.
366 ** First, replace bogus characters.
367 */
368 for (i = 0; i < sp->charcnt; ++i)
369 if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
370 sp->chars[i] = TZ_ABBR_ERR_CHAR;
371 /*
372 ** Second, truncate long abbreviations.
373 */
374 for (i = 0; i < sp->typecnt; ++i) {
375 register const struct ttinfo * const ttisp = &sp->ttis[i];
376 register char * cp = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800377
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700378 if (strlen(cp) > TZ_ABBR_MAX_LEN &&
379 strcmp(cp, GRANDPARENTED) != 0)
380 *(cp + TZ_ABBR_MAX_LEN) = '\0';
381 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800382}
383
384static int
385differ_by_repeat(t1, t0)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700386const time_t t1;
387const time_t t0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800388{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700389 if (TYPE_INTEGRAL(time_t) &&
390 TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
391 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800392 return (t1 - t0) == SECSPERREPEAT;
393}
394
395static int toint(unsigned char *s) {
396 return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
397}
398
399static int
400tzload(name, sp, doextend)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700401register const char * name;
402register struct state * const sp;
403register const int doextend;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800404{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700405 register const char * p;
406 register int i;
407 register int fid;
408 register int stored;
409 register int nread;
410 union {
411 struct tzhead tzhead;
412 char buf[2 * sizeof(struct tzhead) +
413 2 * sizeof *sp +
414 4 * TZ_MAX_TIMES];
415 } u;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800416 int toread = sizeof u.buf;
417
418 if (name == NULL && (name = TZDEFAULT) == NULL) {
419 XLOG(("tzload: null 'name' parameter\n" ));
420 return -1;
421 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700422 {
423 register int doaccess;
424 /*
425 ** Section 4.9.1 of the C standard says that
426 ** "FILENAME_MAX expands to an integral constant expression
427 ** that is the size needed for an array of char large enough
428 ** to hold the longest file name string that the implementation
429 ** guarantees can be opened."
430 */
431 char fullname[FILENAME_MAX + 1];
432 char *origname = (char*) name;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800433
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700434 if (name[0] == ':')
435 ++name;
436 doaccess = name[0] == '/';
437 if (!doaccess) {
438 if ((p = TZDIR) == NULL) {
439 XLOG(("tzload: null TZDIR macro ?\n" ));
440 return -1;
441 }
442 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) {
443 XLOG(( "tzload: path too long: %s/%s\n", p, name ));
444 return -1;
445 }
446 (void) strcpy(fullname, p);
447 (void) strcat(fullname, "/");
448 (void) strcat(fullname, name);
449 /*
450 ** Set doaccess if '.' (as in "../") shows up in name.
451 */
452 if (strchr(name, '.') != NULL)
453 doaccess = TRUE;
454 name = fullname;
455 }
456 if (doaccess && access(name, R_OK) != 0) {
457 XLOG(( "tzload: could not find '%s'\n", name ));
458 return -1;
459 }
460 if ((fid = open(name, OPEN_MODE)) == -1) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800461 char buf[READLEN];
462 char name[NAMELEN + 1];
463 int fidix = open(INDEXFILE, OPEN_MODE);
464 int off = -1;
465
466 XLOG(( "tzload: could not open '%s', trying '%s'\n", fullname, INDEXFILE ));
467 if (fidix < 0) {
468 XLOG(( "tzload: could not find '%s'\n", INDEXFILE ));
469 return -1;
470 }
471
472 while (read(fidix, buf, sizeof(buf)) == sizeof(buf)) {
473 memcpy(name, buf, NAMELEN);
474 name[NAMELEN] = '\0';
475
476 if (strcmp(name, origname) == 0) {
477 off = toint((unsigned char *) buf + NAMELEN);
478 toread = toint((unsigned char *) buf + NAMELEN + INTLEN);
479 break;
480 }
481 }
482
483 close(fidix);
484
485 if (off < 0) {
486 XLOG(( "tzload: invalid offset (%d)\n", off ));
487 return -1;
488 }
489
490 fid = open(DATAFILE, OPEN_MODE);
491
492 if (fid < 0) {
493 XLOG(( "tzload: could not open '%s'\n", DATAFILE ));
494 return -1;
495 }
496
497 if (lseek(fid, off, SEEK_SET) < 0) {
498 XLOG(( "tzload: could not seek to %d in '%s'\n", off, DATAFILE ));
499 return -1;
500 }
501 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700502 }
503 nread = read(fid, u.buf, toread);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800504 if (close(fid) < 0 || nread <= 0) {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700505 XLOG(( "tzload: could not read content of '%s'\n", DATAFILE ));
506 return -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800507 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700508 for (stored = 4; stored <= 8; stored *= 2) {
509 int ttisstdcnt;
510 int ttisgmtcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800511
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700512 ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
513 ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
514 sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
515 sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
516 sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
517 sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
518 p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
519 if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
520 sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
521 sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
522 sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
523 (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
524 (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
525 return -1;
526 if (nread - (p - u.buf) <
527 sp->timecnt * stored + /* ats */
528 sp->timecnt + /* types */
529 sp->typecnt * 6 + /* ttinfos */
530 sp->charcnt + /* chars */
531 sp->leapcnt * (stored + 4) + /* lsinfos */
532 ttisstdcnt + /* ttisstds */
533 ttisgmtcnt) /* ttisgmts */
534 return -1;
535 for (i = 0; i < sp->timecnt; ++i) {
536 sp->ats[i] = (stored == 4) ?
537 detzcode(p) : detzcode64(p);
538 p += stored;
539 }
540 for (i = 0; i < sp->timecnt; ++i) {
541 sp->types[i] = (unsigned char) *p++;
542 if (sp->types[i] >= sp->typecnt)
543 return -1;
544 }
545 for (i = 0; i < sp->typecnt; ++i) {
546 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800547
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700548 ttisp = &sp->ttis[i];
549 ttisp->tt_gmtoff = detzcode(p);
550 p += 4;
551 ttisp->tt_isdst = (unsigned char) *p++;
552 if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
553 return -1;
554 ttisp->tt_abbrind = (unsigned char) *p++;
555 if (ttisp->tt_abbrind < 0 ||
556 ttisp->tt_abbrind > sp->charcnt)
557 return -1;
558 }
559 for (i = 0; i < sp->charcnt; ++i)
560 sp->chars[i] = *p++;
561 sp->chars[i] = '\0'; /* ensure '\0' at end */
562 for (i = 0; i < sp->leapcnt; ++i) {
563 register struct lsinfo * lsisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800564
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700565 lsisp = &sp->lsis[i];
566 lsisp->ls_trans = (stored == 4) ?
567 detzcode(p) : detzcode64(p);
568 p += stored;
569 lsisp->ls_corr = detzcode(p);
570 p += 4;
571 }
572 for (i = 0; i < sp->typecnt; ++i) {
573 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800574
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700575 ttisp = &sp->ttis[i];
576 if (ttisstdcnt == 0)
577 ttisp->tt_ttisstd = FALSE;
578 else {
579 ttisp->tt_ttisstd = *p++;
580 if (ttisp->tt_ttisstd != TRUE &&
581 ttisp->tt_ttisstd != FALSE)
582 return -1;
583 }
584 }
585 for (i = 0; i < sp->typecnt; ++i) {
586 register struct ttinfo * ttisp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800587
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700588 ttisp = &sp->ttis[i];
589 if (ttisgmtcnt == 0)
590 ttisp->tt_ttisgmt = FALSE;
591 else {
592 ttisp->tt_ttisgmt = *p++;
593 if (ttisp->tt_ttisgmt != TRUE &&
594 ttisp->tt_ttisgmt != FALSE)
595 return -1;
596 }
597 }
598 /*
599 ** Out-of-sort ats should mean we're running on a
600 ** signed time_t system but using a data file with
601 ** unsigned values (or vice versa).
602 */
603 for (i = 0; i < sp->timecnt - 2; ++i)
604 if (sp->ats[i] > sp->ats[i + 1]) {
605 ++i;
606 if (TYPE_SIGNED(time_t)) {
607 /*
608 ** Ignore the end (easy).
609 */
610 sp->timecnt = i;
611 } else {
612 /*
613 ** Ignore the beginning (harder).
614 */
615 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800616
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700617 for (j = 0; j + i < sp->timecnt; ++j) {
618 sp->ats[j] = sp->ats[j + i];
619 sp->types[j] = sp->types[j + i];
620 }
621 sp->timecnt = j;
622 }
623 break;
624 }
625 /*
626 ** If this is an old file, we're done.
627 */
628 if (u.tzhead.tzh_version[0] == '\0')
629 break;
630 nread -= p - u.buf;
631 for (i = 0; i < nread; ++i)
632 u.buf[i] = p[i];
633 /*
634 ** If this is a narrow integer time_t system, we're done.
635 */
636 if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
637 break;
638 }
639 if (doextend && nread > 2 &&
640 u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
641 sp->typecnt + 2 <= TZ_MAX_TYPES) {
642 struct state ts;
643 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800644
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700645 u.buf[nread - 1] = '\0';
646 result = tzparse(&u.buf[1], &ts, FALSE);
647 if (result == 0 && ts.typecnt == 2 &&
648 sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
649 for (i = 0; i < 2; ++i)
650 ts.ttis[i].tt_abbrind +=
651 sp->charcnt;
652 for (i = 0; i < ts.charcnt; ++i)
653 sp->chars[sp->charcnt++] =
654 ts.chars[i];
655 i = 0;
656 while (i < ts.timecnt &&
657 ts.ats[i] <=
658 sp->ats[sp->timecnt - 1])
659 ++i;
660 while (i < ts.timecnt &&
661 sp->timecnt < TZ_MAX_TIMES) {
662 sp->ats[sp->timecnt] =
663 ts.ats[i];
664 sp->types[sp->timecnt] =
665 sp->typecnt +
666 ts.types[i];
667 ++sp->timecnt;
668 ++i;
669 }
670 sp->ttis[sp->typecnt++] = ts.ttis[0];
671 sp->ttis[sp->typecnt++] = ts.ttis[1];
672 }
673 }
674 i = 2 * YEARSPERREPEAT;
675 sp->goback = sp->goahead = sp->timecnt > i;
676 sp->goback &= sp->types[i] == sp->types[0] &&
677 differ_by_repeat(sp->ats[i], sp->ats[0]);
678 sp->goahead &=
679 sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 1 - i] &&
680 differ_by_repeat(sp->ats[sp->timecnt - 1],
681 sp->ats[sp->timecnt - 1 - i]);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800682 XLOG(( "tzload: load ok !!\n" ));
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700683 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800684}
685
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700686static const int mon_lengths[2][MONSPERYEAR] = {
687 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
688 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800689};
690
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700691static const int year_lengths[2] = {
692 DAYSPERNYEAR, DAYSPERLYEAR
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800693};
694
695/*
696** Given a pointer into a time zone string, scan until a character that is not
697** a valid character in a zone name is found. Return a pointer to that
698** character.
699*/
700
701static const char *
702getzname(strp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700703register const char * strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800704{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700705 register char c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800706
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700707 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
708 c != '+')
709 ++strp;
710 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800711}
712
713/*
714** Given a pointer into an extended time zone string, scan until the ending
715** delimiter of the zone name is located. Return a pointer to the delimiter.
716**
717** As with getzname above, the legal character set is actually quite
718** restricted, with other characters producing undefined results.
719** We don't do any checking here; checking is done later in common-case code.
720*/
721
722static const char *
723getqzname(register const char *strp, const int delim)
724{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700725 register int c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800726
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700727 while ((c = *strp) != '\0' && c != delim)
728 ++strp;
729 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800730}
731
732/*
733** Given a pointer into a time zone string, extract a number from that string.
734** Check that the number is within a specified range; if it is not, return
735** NULL.
736** Otherwise, return a pointer to the first character not part of the number.
737*/
738
739static const char *
740getnum(strp, nump, min, max)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700741register const char * strp;
742int * const nump;
743const int min;
744const int max;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800745{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700746 register char c;
747 register int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800748
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700749 if (strp == NULL || !is_digit(c = *strp))
750 return NULL;
751 num = 0;
752 do {
753 num = num * 10 + (c - '0');
754 if (num > max)
755 return NULL; /* illegal value */
756 c = *++strp;
757 } while (is_digit(c));
758 if (num < min)
759 return NULL; /* illegal value */
760 *nump = num;
761 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800762}
763
764/*
765** Given a pointer into a time zone string, extract a number of seconds,
766** in hh[:mm[:ss]] form, from the string.
767** If any error occurs, return NULL.
768** Otherwise, return a pointer to the first character not part of the number
769** of seconds.
770*/
771
772static const char *
773getsecs(strp, secsp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700774register const char * strp;
775long * const secsp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800776{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700777 int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800778
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700779 /*
780 ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
781 ** "M10.4.6/26", which does not conform to Posix,
782 ** but which specifies the equivalent of
783 ** ``02:00 on the first Sunday on or after 23 Oct''.
784 */
785 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
786 if (strp == NULL)
787 return NULL;
788 *secsp = num * (long) SECSPERHOUR;
789 if (*strp == ':') {
790 ++strp;
791 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
792 if (strp == NULL)
793 return NULL;
794 *secsp += num * SECSPERMIN;
795 if (*strp == ':') {
796 ++strp;
797 /* `SECSPERMIN' allows for leap seconds. */
798 strp = getnum(strp, &num, 0, SECSPERMIN);
799 if (strp == NULL)
800 return NULL;
801 *secsp += num;
802 }
803 }
804 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800805}
806
807/*
808** Given a pointer into a time zone string, extract an offset, in
809** [+-]hh[:mm[:ss]] form, from the string.
810** If any error occurs, return NULL.
811** Otherwise, return a pointer to the first character not part of the time.
812*/
813
814static const char *
815getoffset(strp, offsetp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700816register const char * strp;
817long * const offsetp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800818{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700819 register int neg = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800820
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700821 if (*strp == '-') {
822 neg = 1;
823 ++strp;
824 } else if (*strp == '+')
825 ++strp;
826 strp = getsecs(strp, offsetp);
827 if (strp == NULL)
828 return NULL; /* illegal time */
829 if (neg)
830 *offsetp = -*offsetp;
831 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800832}
833
834/*
835** Given a pointer into a time zone string, extract a rule in the form
836** date[/time]. See POSIX section 8 for the format of "date" and "time".
837** If a valid rule is not found, return NULL.
838** Otherwise, return a pointer to the first character not part of the rule.
839*/
840
841static const char *
842getrule(strp, rulep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700843const char * strp;
844register struct rule * const rulep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800845{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700846 if (*strp == 'J') {
847 /*
848 ** Julian day.
849 */
850 rulep->r_type = JULIAN_DAY;
851 ++strp;
852 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
853 } else if (*strp == 'M') {
854 /*
855 ** Month, week, day.
856 */
857 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
858 ++strp;
859 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
860 if (strp == NULL)
861 return NULL;
862 if (*strp++ != '.')
863 return NULL;
864 strp = getnum(strp, &rulep->r_week, 1, 5);
865 if (strp == NULL)
866 return NULL;
867 if (*strp++ != '.')
868 return NULL;
869 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
870 } else if (is_digit(*strp)) {
871 /*
872 ** Day of year.
873 */
874 rulep->r_type = DAY_OF_YEAR;
875 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
876 } else return NULL; /* invalid format */
877 if (strp == NULL)
878 return NULL;
879 if (*strp == '/') {
880 /*
881 ** Time specified.
882 */
883 ++strp;
884 strp = getsecs(strp, &rulep->r_time);
885 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
886 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800887}
888
889/*
890** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
891** year, a rule, and the offset from UTC at the time that rule takes effect,
892** calculate the Epoch-relative time that rule takes effect.
893*/
894
895static time_t
896transtime(janfirst, year, rulep, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700897const time_t janfirst;
898const int year;
899register const struct rule * const rulep;
900const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800901{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700902 register int leapyear;
903 register time_t value;
904 register int i;
905 int d, m1, yy0, yy1, yy2, dow;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800906
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700907 INITIALIZE(value);
908 leapyear = isleap(year);
909 switch (rulep->r_type) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800910
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700911 case JULIAN_DAY:
912 /*
913 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
914 ** years.
915 ** In non-leap years, or if the day number is 59 or less, just
916 ** add SECSPERDAY times the day number-1 to the time of
917 ** January 1, midnight, to get the day.
918 */
919 value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
920 if (leapyear && rulep->r_day >= 60)
921 value += SECSPERDAY;
922 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800923
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700924 case DAY_OF_YEAR:
925 /*
926 ** n - day of year.
927 ** Just add SECSPERDAY times the day number to the time of
928 ** January 1, midnight, to get the day.
929 */
930 value = janfirst + rulep->r_day * SECSPERDAY;
931 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800932
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700933 case MONTH_NTH_DAY_OF_WEEK:
934 /*
935 ** Mm.n.d - nth "dth day" of month m.
936 */
937 value = janfirst;
938 for (i = 0; i < rulep->r_mon - 1; ++i)
939 value += mon_lengths[leapyear][i] * SECSPERDAY;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800940
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700941 /*
942 ** Use Zeller's Congruence to get day-of-week of first day of
943 ** month.
944 */
945 m1 = (rulep->r_mon + 9) % 12 + 1;
946 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
947 yy1 = yy0 / 100;
948 yy2 = yy0 % 100;
949 dow = ((26 * m1 - 2) / 10 +
950 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
951 if (dow < 0)
952 dow += DAYSPERWEEK;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800953
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700954 /*
955 ** "dow" is the day-of-week of the first day of the month. Get
956 ** the day-of-month (zero-origin) of the first "dow" day of the
957 ** month.
958 */
959 d = rulep->r_day - dow;
960 if (d < 0)
961 d += DAYSPERWEEK;
962 for (i = 1; i < rulep->r_week; ++i) {
963 if (d + DAYSPERWEEK >=
964 mon_lengths[leapyear][rulep->r_mon - 1])
965 break;
966 d += DAYSPERWEEK;
967 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800968
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700969 /*
970 ** "d" is the day-of-month (zero-origin) of the day we want.
971 */
972 value += d * SECSPERDAY;
973 break;
974 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800975
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700976 /*
977 ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
978 ** question. To get the Epoch-relative time of the specified local
979 ** time on that day, add the transition time and the current offset
980 ** from UTC.
981 */
982 return value + rulep->r_time + offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800983}
984
985/*
986** Given a POSIX section 8-style TZ string, fill in the rule tables as
987** appropriate.
988*/
989
990static int
991tzparse(name, sp, lastditch)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700992const char * name;
993register struct state * const sp;
994const int lastditch;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800995{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700996 const char * stdname;
997 const char * dstname;
998 size_t stdlen;
999 size_t dstlen;
1000 long stdoffset;
1001 long dstoffset;
1002 register time_t * atp;
1003 register unsigned char * typep;
1004 register char * cp;
1005 register int load_result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001006
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001007 INITIALIZE(dstname);
1008 stdname = name;
1009 if (lastditch) {
1010 stdlen = strlen(name); /* length of standard zone name */
1011 name += stdlen;
1012 if (stdlen >= sizeof sp->chars)
1013 stdlen = (sizeof sp->chars) - 1;
1014 stdoffset = 0;
1015 } else {
1016 if (*name == '<') {
1017 name++;
1018 stdname = name;
1019 name = getqzname(name, '>');
1020 if (*name != '>')
1021 return (-1);
1022 stdlen = name - stdname;
1023 name++;
1024 } else {
1025 name = getzname(name);
1026 stdlen = name - stdname;
1027 }
1028 if (*name == '\0')
1029 return -1;
1030 name = getoffset(name, &stdoffset);
1031 if (name == NULL)
1032 return -1;
1033 }
1034 load_result = tzload(TZDEFRULES, sp, FALSE);
1035 if (load_result != 0)
1036 sp->leapcnt = 0; /* so, we're off a little */
1037 sp->timecnt = 0;
1038 if (*name != '\0') {
1039 if (*name == '<') {
1040 dstname = ++name;
1041 name = getqzname(name, '>');
1042 if (*name != '>')
1043 return -1;
1044 dstlen = name - dstname;
1045 name++;
1046 } else {
1047 dstname = name;
1048 name = getzname(name);
1049 dstlen = name - dstname; /* length of DST zone name */
1050 }
1051 if (*name != '\0' && *name != ',' && *name != ';') {
1052 name = getoffset(name, &dstoffset);
1053 if (name == NULL)
1054 return -1;
1055 } else dstoffset = stdoffset - SECSPERHOUR;
1056 if (*name == '\0' && load_result != 0)
1057 name = TZDEFRULESTRING;
1058 if (*name == ',' || *name == ';') {
1059 struct rule start;
1060 struct rule end;
1061 register int year;
1062 register time_t janfirst;
1063 time_t starttime;
1064 time_t endtime;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001065
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001066 ++name;
1067 if ((name = getrule(name, &start)) == NULL)
1068 return -1;
1069 if (*name++ != ',')
1070 return -1;
1071 if ((name = getrule(name, &end)) == NULL)
1072 return -1;
1073 if (*name != '\0')
1074 return -1;
1075 sp->typecnt = 2; /* standard time and DST */
1076 /*
1077 ** Two transitions per year, from EPOCH_YEAR forward.
1078 */
1079 sp->ttis[0].tt_gmtoff = -dstoffset;
1080 sp->ttis[0].tt_isdst = 1;
1081 sp->ttis[0].tt_abbrind = stdlen + 1;
1082 sp->ttis[1].tt_gmtoff = -stdoffset;
1083 sp->ttis[1].tt_isdst = 0;
1084 sp->ttis[1].tt_abbrind = 0;
1085 atp = sp->ats;
1086 typep = sp->types;
1087 janfirst = 0;
1088 for (year = EPOCH_YEAR;
1089 sp->timecnt + 2 <= TZ_MAX_TIMES;
1090 ++year) {
1091 time_t newfirst;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001092
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001093 starttime = transtime(janfirst, year, &start,
1094 stdoffset);
1095 endtime = transtime(janfirst, year, &end,
1096 dstoffset);
1097 if (starttime > endtime) {
1098 *atp++ = endtime;
1099 *typep++ = 1; /* DST ends */
1100 *atp++ = starttime;
1101 *typep++ = 0; /* DST begins */
1102 } else {
1103 *atp++ = starttime;
1104 *typep++ = 0; /* DST begins */
1105 *atp++ = endtime;
1106 *typep++ = 1; /* DST ends */
1107 }
1108 sp->timecnt += 2;
1109 newfirst = janfirst;
1110 newfirst += year_lengths[isleap(year)] *
1111 SECSPERDAY;
1112 if (newfirst <= janfirst)
1113 break;
1114 janfirst = newfirst;
1115 }
1116 } else {
1117 register long theirstdoffset;
1118 register long theirdstoffset;
1119 register long theiroffset;
1120 register int isdst;
1121 register int i;
1122 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001123
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001124 if (*name != '\0')
1125 return -1;
1126 /*
1127 ** Initial values of theirstdoffset and theirdstoffset.
1128 */
1129 theirstdoffset = 0;
1130 for (i = 0; i < sp->timecnt; ++i) {
1131 j = sp->types[i];
1132 if (!sp->ttis[j].tt_isdst) {
1133 theirstdoffset =
1134 -sp->ttis[j].tt_gmtoff;
1135 break;
1136 }
1137 }
1138 theirdstoffset = 0;
1139 for (i = 0; i < sp->timecnt; ++i) {
1140 j = sp->types[i];
1141 if (sp->ttis[j].tt_isdst) {
1142 theirdstoffset =
1143 -sp->ttis[j].tt_gmtoff;
1144 break;
1145 }
1146 }
1147 /*
1148 ** Initially we're assumed to be in standard time.
1149 */
1150 isdst = FALSE;
1151 theiroffset = theirstdoffset;
1152 /*
1153 ** Now juggle transition times and types
1154 ** tracking offsets as you do.
1155 */
1156 for (i = 0; i < sp->timecnt; ++i) {
1157 j = sp->types[i];
1158 sp->types[i] = sp->ttis[j].tt_isdst;
1159 if (sp->ttis[j].tt_ttisgmt) {
1160 /* No adjustment to transition time */
1161 } else {
1162 /*
1163 ** If summer time is in effect, and the
1164 ** transition time was not specified as
1165 ** standard time, add the summer time
1166 ** offset to the transition time;
1167 ** otherwise, add the standard time
1168 ** offset to the transition time.
1169 */
1170 /*
1171 ** Transitions from DST to DDST
1172 ** will effectively disappear since
1173 ** POSIX provides for only one DST
1174 ** offset.
1175 */
1176 if (isdst && !sp->ttis[j].tt_ttisstd) {
1177 sp->ats[i] += dstoffset -
1178 theirdstoffset;
1179 } else {
1180 sp->ats[i] += stdoffset -
1181 theirstdoffset;
1182 }
1183 }
1184 theiroffset = -sp->ttis[j].tt_gmtoff;
1185 if (sp->ttis[j].tt_isdst)
1186 theirdstoffset = theiroffset;
1187 else theirstdoffset = theiroffset;
1188 }
1189 /*
1190 ** Finally, fill in ttis.
1191 ** ttisstd and ttisgmt need not be handled.
1192 */
1193 sp->ttis[0].tt_gmtoff = -stdoffset;
1194 sp->ttis[0].tt_isdst = FALSE;
1195 sp->ttis[0].tt_abbrind = 0;
1196 sp->ttis[1].tt_gmtoff = -dstoffset;
1197 sp->ttis[1].tt_isdst = TRUE;
1198 sp->ttis[1].tt_abbrind = stdlen + 1;
1199 sp->typecnt = 2;
1200 }
1201 } else {
1202 dstlen = 0;
1203 sp->typecnt = 1; /* only standard time */
1204 sp->timecnt = 0;
1205 sp->ttis[0].tt_gmtoff = -stdoffset;
1206 sp->ttis[0].tt_isdst = 0;
1207 sp->ttis[0].tt_abbrind = 0;
1208 }
1209 sp->charcnt = stdlen + 1;
1210 if (dstlen != 0)
1211 sp->charcnt += dstlen + 1;
1212 if ((size_t) sp->charcnt > sizeof sp->chars)
1213 return -1;
1214 cp = sp->chars;
1215 (void) strncpy(cp, stdname, stdlen);
1216 cp += stdlen;
1217 *cp++ = '\0';
1218 if (dstlen != 0) {
1219 (void) strncpy(cp, dstname, dstlen);
1220 *(cp + dstlen) = '\0';
1221 }
1222 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001223}
1224
1225static void
1226gmtload(sp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001227struct state * const sp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001228{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001229 if (tzload(gmt, sp, TRUE) != 0)
1230 (void) tzparse(gmt, sp, TRUE);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001231}
1232
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001233static void
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001234tzsetwall P((void))
1235{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001236 if (lcl_is_set < 0)
1237 return;
1238 lcl_is_set = -1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001239
1240#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001241 if (lclptr == NULL) {
1242 lclptr = (struct state *) malloc(sizeof *lclptr);
1243 if (lclptr == NULL) {
1244 settzname(); /* all we can do */
1245 return;
1246 }
1247 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001248#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001249 if (tzload((char *) NULL, lclptr, TRUE) != 0)
1250 gmtload(lclptr);
1251 settzname();
1252}
1253
1254static void
1255tzset_locked P((void))
1256{
1257 register const char * name = NULL;
1258 static char buf[PROP_VALUE_MAX];
1259
1260 name = getenv("TZ");
1261
1262 // try the "persist.sys.timezone" system property first
1263 if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0)
1264 name = buf;
1265
1266 if (name == NULL) {
1267 tzsetwall();
1268 return;
1269 }
1270
1271 if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
1272 return;
1273 lcl_is_set = strlen(name) < sizeof lcl_TZname;
1274 if (lcl_is_set)
1275 (void) strcpy(lcl_TZname, name);
1276
1277#ifdef ALL_STATE
1278 if (lclptr == NULL) {
1279 lclptr = (struct state *) malloc(sizeof *lclptr);
1280 if (lclptr == NULL) {
1281 settzname(); /* all we can do */
1282 return;
1283 }
1284 }
1285#endif /* defined ALL_STATE */
1286 if (*name == '\0') {
1287 /*
1288 ** User wants it fast rather than right.
1289 */
1290 lclptr->leapcnt = 0; /* so, we're off a little */
1291 lclptr->timecnt = 0;
1292 lclptr->typecnt = 0;
1293 lclptr->ttis[0].tt_isdst = 0;
1294 lclptr->ttis[0].tt_gmtoff = 0;
1295 lclptr->ttis[0].tt_abbrind = 0;
1296 (void) strcpy(lclptr->chars, gmt);
1297 } else if (tzload(name, lclptr, TRUE) != 0)
1298 if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
1299 (void) gmtload(lclptr);
1300 settzname();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001301}
1302
1303void
1304tzset P((void))
1305{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001306 _tzLock();
1307 tzset_locked();
1308 _tzUnlock();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001309}
1310
1311/*
1312** The easy way to behave "as if no library function calls" localtime
1313** is to not call it--so we drop its guts into "localsub", which can be
1314** freely called. (And no, the PANS doesn't require the above behavior--
1315** but it *is* desirable.)
1316**
1317** The unused offset argument is for the benefit of mktime variants.
1318*/
1319
1320/*ARGSUSED*/
1321static struct tm *
1322localsub(timep, offset, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001323const time_t * const timep;
1324const long offset;
1325struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001326{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001327 register struct state * sp;
1328 register const struct ttinfo * ttisp;
1329 register int i;
1330 register struct tm * result;
1331 const time_t t = *timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001332
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001333 sp = lclptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001334#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001335 if (sp == NULL)
1336 return gmtsub(timep, offset, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001337#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001338 if ((sp->goback && t < sp->ats[0]) ||
1339 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1340 time_t newt = t;
1341 register time_t seconds;
1342 register time_t tcycles;
1343 register int_fast64_t icycles;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001344
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001345 if (t < sp->ats[0])
1346 seconds = sp->ats[0] - t;
1347 else seconds = t - sp->ats[sp->timecnt - 1];
1348 --seconds;
1349 tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1350 ++tcycles;
1351 icycles = tcycles;
1352 if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1353 return NULL;
1354 seconds = icycles;
1355 seconds *= YEARSPERREPEAT;
1356 seconds *= AVGSECSPERYEAR;
1357 if (t < sp->ats[0])
1358 newt += seconds;
1359 else newt -= seconds;
1360 if (newt < sp->ats[0] ||
1361 newt > sp->ats[sp->timecnt - 1])
1362 return NULL; /* "cannot happen" */
1363 result = localsub(&newt, offset, tmp);
1364 if (result == tmp) {
1365 register time_t newy;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001366
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001367 newy = tmp->tm_year;
1368 if (t < sp->ats[0])
1369 newy -= icycles * YEARSPERREPEAT;
1370 else newy += icycles * YEARSPERREPEAT;
1371 tmp->tm_year = newy;
1372 if (tmp->tm_year != newy)
1373 return NULL;
1374 }
1375 return result;
1376 }
1377 if (sp->timecnt == 0 || t < sp->ats[0]) {
1378 i = 0;
1379 while (sp->ttis[i].tt_isdst)
1380 if (++i >= sp->typecnt) {
1381 i = 0;
1382 break;
1383 }
1384 } else {
1385 register int lo = 1;
1386 register int hi = sp->timecnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001387
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001388 while (lo < hi) {
1389 register int mid = (lo + hi) >> 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001390
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001391 if (t < sp->ats[mid])
1392 hi = mid;
1393 else lo = mid + 1;
1394 }
1395 i = (int) sp->types[lo - 1];
1396 }
1397 ttisp = &sp->ttis[i];
1398 /*
1399 ** To get (wrong) behavior that's compatible with System V Release 2.0
1400 ** you'd replace the statement below with
1401 ** t += ttisp->tt_gmtoff;
1402 ** timesub(&t, 0L, sp, tmp);
1403 */
1404 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1405 tmp->tm_isdst = ttisp->tt_isdst;
1406 tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001407#ifdef TM_ZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001408 tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001409#endif /* defined TM_ZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001410 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001411}
1412
1413struct tm *
1414localtime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001415const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001416{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001417 return localtime_r(timep, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001418}
1419
1420/*
1421** Re-entrant version of localtime.
1422*/
1423
1424struct tm *
1425localtime_r(timep, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001426const time_t * const timep;
1427struct tm * tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001428{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001429 struct tm* result;
1430
1431 _tzLock();
1432 tzset_locked();
1433 result = localsub(timep, 0L, tmp);
1434 _tzUnlock();
1435
1436 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001437}
1438
1439/*
1440** gmtsub is to gmtime as localsub is to localtime.
1441*/
1442
1443static struct tm *
1444gmtsub(timep, offset, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001445const time_t * const timep;
1446const long offset;
1447struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001448{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001449 register struct tm * result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001450
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001451 if (!gmt_is_set) {
1452 gmt_is_set = TRUE;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001453#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001454 gmtptr = (struct state *) malloc(sizeof *gmtptr);
1455 if (gmtptr != NULL)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001456#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001457 gmtload(gmtptr);
1458 }
1459 result = timesub(timep, offset, gmtptr, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001460#ifdef TM_ZONE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001461 /*
1462 ** Could get fancy here and deliver something such as
1463 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
1464 ** but this is no time for a treasure hunt.
1465 */
1466 if (offset != 0)
1467 tmp->TM_ZONE = wildabbr;
1468 else {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001469#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001470 if (gmtptr == NULL)
1471 tmp->TM_ZONE = gmt;
1472 else tmp->TM_ZONE = gmtptr->chars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001473#endif /* defined ALL_STATE */
1474#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001475 tmp->TM_ZONE = gmtptr->chars;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001476#endif /* State Farm */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001477 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001478#endif /* defined TM_ZONE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001479 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001480}
1481
1482struct tm *
1483gmtime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001484const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001485{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001486 return gmtime_r(timep, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001487}
1488
1489/*
1490* Re-entrant version of gmtime.
1491*/
1492
1493struct tm *
1494gmtime_r(timep, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001495const time_t * const timep;
1496struct tm * tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001497{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001498 struct tm* result;
1499
1500 _tzLock();
1501 result = gmtsub(timep, 0L, tmp);
1502 _tzUnlock();
1503
1504 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001505}
1506
1507#ifdef STD_INSPIRED
1508
1509struct tm *
1510offtime(timep, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001511const time_t * const timep;
1512const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001513{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001514 return gmtsub(timep, offset, &tmGlobal);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001515}
1516
1517#endif /* defined STD_INSPIRED */
1518
1519/*
1520** Return the number of leap years through the end of the given year
1521** where, to make the math easy, the answer for year zero is defined as zero.
1522*/
1523
1524static int
1525leaps_thru_end_of(y)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001526register const int y;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001527{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001528 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1529 -(leaps_thru_end_of(-(y + 1)) + 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001530}
1531
1532static struct tm *
1533timesub(timep, offset, sp, tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001534const time_t * const timep;
1535const long offset;
1536register const struct state * const sp;
1537register struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001538{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001539 register const struct lsinfo * lp;
1540 register time_t tdays;
1541 register int idays; /* unsigned would be so 2003 */
1542 register long rem;
1543 int y;
1544 register const int * ip;
1545 register long corr;
1546 register int hit;
1547 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001548
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001549 corr = 0;
1550 hit = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001551#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001552 i = (sp == NULL) ? 0 : sp->leapcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001553#endif /* defined ALL_STATE */
1554#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001555 i = sp->leapcnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001556#endif /* State Farm */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001557 while (--i >= 0) {
1558 lp = &sp->lsis[i];
1559 if (*timep >= lp->ls_trans) {
1560 if (*timep == lp->ls_trans) {
1561 hit = ((i == 0 && lp->ls_corr > 0) ||
1562 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1563 if (hit)
1564 while (i > 0 &&
1565 sp->lsis[i].ls_trans ==
1566 sp->lsis[i - 1].ls_trans + 1 &&
1567 sp->lsis[i].ls_corr ==
1568 sp->lsis[i - 1].ls_corr + 1) {
1569 ++hit;
1570 --i;
1571 }
1572 }
1573 corr = lp->ls_corr;
1574 break;
1575 }
1576 }
1577 y = EPOCH_YEAR;
1578 tdays = *timep / SECSPERDAY;
1579 rem = *timep - tdays * SECSPERDAY;
1580 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1581 int newy;
1582 register time_t tdelta;
1583 register int idelta;
1584 register int leapdays;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001585
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001586 tdelta = tdays / DAYSPERLYEAR;
1587 idelta = tdelta;
1588 if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
1589 return NULL;
1590 if (idelta == 0)
1591 idelta = (tdays < 0) ? -1 : 1;
1592 newy = y;
1593 if (increment_overflow(&newy, idelta))
1594 return NULL;
1595 leapdays = leaps_thru_end_of(newy - 1) -
1596 leaps_thru_end_of(y - 1);
1597 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1598 tdays -= leapdays;
1599 y = newy;
1600 }
1601 {
1602 register long seconds;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001603
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001604 seconds = tdays * SECSPERDAY + 0.5;
1605 tdays = seconds / SECSPERDAY;
1606 rem += seconds - tdays * SECSPERDAY;
1607 }
1608 /*
1609 ** Given the range, we can now fearlessly cast...
1610 */
1611 idays = tdays;
1612 rem += offset - corr;
1613 while (rem < 0) {
1614 rem += SECSPERDAY;
1615 --idays;
1616 }
1617 while (rem >= SECSPERDAY) {
1618 rem -= SECSPERDAY;
1619 ++idays;
1620 }
1621 while (idays < 0) {
1622 if (increment_overflow(&y, -1))
1623 return NULL;
1624 idays += year_lengths[isleap(y)];
1625 }
1626 while (idays >= year_lengths[isleap(y)]) {
1627 idays -= year_lengths[isleap(y)];
1628 if (increment_overflow(&y, 1))
1629 return NULL;
1630 }
1631 tmp->tm_year = y;
1632 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1633 return NULL;
1634 tmp->tm_yday = idays;
1635 /*
1636 ** The "extra" mods below avoid overflow problems.
1637 */
1638 tmp->tm_wday = EPOCH_WDAY +
1639 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
1640 (DAYSPERNYEAR % DAYSPERWEEK) +
1641 leaps_thru_end_of(y - 1) -
1642 leaps_thru_end_of(EPOCH_YEAR - 1) +
1643 idays;
1644 tmp->tm_wday %= DAYSPERWEEK;
1645 if (tmp->tm_wday < 0)
1646 tmp->tm_wday += DAYSPERWEEK;
1647 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1648 rem %= SECSPERHOUR;
1649 tmp->tm_min = (int) (rem / SECSPERMIN);
1650 /*
1651 ** A positive leap second requires a special
1652 ** representation. This uses "... ??:59:60" et seq.
1653 */
1654 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1655 ip = mon_lengths[isleap(y)];
1656 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1657 idays -= ip[tmp->tm_mon];
1658 tmp->tm_mday = (int) (idays + 1);
1659 tmp->tm_isdst = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001660#ifdef TM_GMTOFF
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001661 tmp->TM_GMTOFF = offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001662#endif /* defined TM_GMTOFF */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001663 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001664}
1665
1666char *
1667ctime(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001668const time_t * const timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001669{
1670/*
1671** Section 4.12.3.2 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001672** The ctime function converts the calendar time pointed to by timer
1673** to local time in the form of a string. It is equivalent to
1674** asctime(localtime(timer))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001675*/
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001676 return asctime(localtime(timep));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001677}
1678
1679char *
1680ctime_r(timep, buf)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001681const time_t * const timep;
1682char * buf;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001683{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001684 struct tm mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001685
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001686 return asctime_r(localtime_r(timep, &mytm), buf);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001687}
1688
1689/*
1690** Adapted from code provided by Robert Elz, who writes:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001691** The "best" way to do mktime I think is based on an idea of Bob
1692** Kridle's (so its said...) from a long time ago.
1693** It does a binary search of the time_t space. Since time_t's are
1694** just 32 bits, its a max of 32 iterations (even at 64 bits it
1695** would still be very reasonable).
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001696*/
1697
1698#ifndef WRONG
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001699#define WRONG (-1)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001700#endif /* !defined WRONG */
1701
1702/*
1703** Simplified normalize logic courtesy Paul Eggert.
1704*/
1705
1706static int
1707increment_overflow(number, delta)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001708int * number;
1709int delta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001710{
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001711 unsigned number0 = (unsigned)*number;
1712 unsigned number1 = (unsigned)(number0 + delta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001713
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001714 *number = (int)number1;
1715
1716 if (delta >= 0) {
1717 return ((int)number1 < (int)number0);
1718 } else {
1719 return ((int)number1 > (int)number0);
1720 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001721}
1722
1723static int
1724long_increment_overflow(number, delta)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001725long * number;
1726int delta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001727{
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001728 unsigned long number0 = (unsigned long)*number;
1729 unsigned long number1 = (unsigned long)(number0 + delta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001730
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001731 *number = (long)number1;
1732
1733 if (delta >= 0) {
1734 return ((long)number1 < (long)number0);
1735 } else {
1736 return ((long)number1 > (long)number0);
1737 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001738}
1739
1740static int
1741normalize_overflow(tensptr, unitsptr, base)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001742int * const tensptr;
1743int * const unitsptr;
1744const int base;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001745{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001746 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001747
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001748 tensdelta = (*unitsptr >= 0) ?
1749 (*unitsptr / base) :
1750 (-1 - (-1 - *unitsptr) / base);
1751 *unitsptr -= tensdelta * base;
1752 return increment_overflow(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001753}
1754
1755static int
1756long_normalize_overflow(tensptr, unitsptr, base)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001757long * const tensptr;
1758int * const unitsptr;
1759const int base;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001760{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001761 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001762
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001763 tensdelta = (*unitsptr >= 0) ?
1764 (*unitsptr / base) :
1765 (-1 - (-1 - *unitsptr) / base);
1766 *unitsptr -= tensdelta * base;
1767 return long_increment_overflow(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001768}
1769
1770static int
1771tmcomp(atmp, btmp)
1772register const struct tm * const atmp;
1773register const struct tm * const btmp;
1774{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001775 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001776
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001777 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1778 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1779 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1780 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1781 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1782 result = atmp->tm_sec - btmp->tm_sec;
1783 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001784}
1785
1786static time_t
1787time2sub(tmp, funcp, offset, okayp, do_norm_secs)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001788struct tm * const tmp;
1789struct tm * (* const funcp) P((const time_t*, long, struct tm*));
1790const long offset;
1791int * const okayp;
1792const int do_norm_secs;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001793{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001794 register const struct state * sp;
1795 register int dir;
1796 register int i, j;
1797 register int saved_seconds;
1798 register long li;
1799 register time_t lo;
1800 register time_t hi;
1801 long y;
1802 time_t newt;
1803 time_t t;
1804 struct tm yourtm, mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001805
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001806 *okayp = FALSE;
1807 yourtm = *tmp;
1808 if (do_norm_secs) {
1809 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1810 SECSPERMIN))
1811 return WRONG;
1812 }
1813 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1814 return WRONG;
1815 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1816 return WRONG;
1817 y = yourtm.tm_year;
1818 if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
1819 return WRONG;
1820 /*
1821 ** Turn y into an actual year number for now.
1822 ** It is converted back to an offset from TM_YEAR_BASE later.
1823 */
1824 if (long_increment_overflow(&y, TM_YEAR_BASE))
1825 return WRONG;
1826 while (yourtm.tm_mday <= 0) {
1827 if (long_increment_overflow(&y, -1))
1828 return WRONG;
1829 li = y + (1 < yourtm.tm_mon);
1830 yourtm.tm_mday += year_lengths[isleap(li)];
1831 }
1832 while (yourtm.tm_mday > DAYSPERLYEAR) {
1833 li = y + (1 < yourtm.tm_mon);
1834 yourtm.tm_mday -= year_lengths[isleap(li)];
1835 if (long_increment_overflow(&y, 1))
1836 return WRONG;
1837 }
1838 for ( ; ; ) {
1839 i = mon_lengths[isleap(y)][yourtm.tm_mon];
1840 if (yourtm.tm_mday <= i)
1841 break;
1842 yourtm.tm_mday -= i;
1843 if (++yourtm.tm_mon >= MONSPERYEAR) {
1844 yourtm.tm_mon = 0;
1845 if (long_increment_overflow(&y, 1))
1846 return WRONG;
1847 }
1848 }
1849 if (long_increment_overflow(&y, -TM_YEAR_BASE))
1850 return WRONG;
1851 yourtm.tm_year = y;
1852 if (yourtm.tm_year != y)
1853 return WRONG;
1854 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
1855 saved_seconds = 0;
1856 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
1857 /*
1858 ** We can't set tm_sec to 0, because that might push the
1859 ** time below the minimum representable time.
1860 ** Set tm_sec to 59 instead.
1861 ** This assumes that the minimum representable time is
1862 ** not in the same minute that a leap second was deleted from,
1863 ** which is a safer assumption than using 58 would be.
1864 */
1865 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1866 return WRONG;
1867 saved_seconds = yourtm.tm_sec;
1868 yourtm.tm_sec = SECSPERMIN - 1;
1869 } else {
1870 saved_seconds = yourtm.tm_sec;
1871 yourtm.tm_sec = 0;
1872 }
1873 /*
1874 ** Do a binary search (this works whatever time_t's type is).
1875 */
1876 if (!TYPE_SIGNED(time_t)) {
1877 lo = 0;
1878 hi = lo - 1;
1879 } else if (!TYPE_INTEGRAL(time_t)) {
1880 if (sizeof(time_t) > sizeof(float))
1881 hi = (time_t) DBL_MAX;
1882 else hi = (time_t) FLT_MAX;
1883 lo = -hi;
1884 } else {
1885 lo = 1;
1886 for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
1887 lo *= 2;
1888 hi = -(lo + 1);
1889 }
1890 for ( ; ; ) {
1891 t = lo / 2 + hi / 2;
1892 if (t < lo)
1893 t = lo;
1894 else if (t > hi)
1895 t = hi;
1896 if ((*funcp)(&t, offset, &mytm) == NULL) {
1897 /*
1898 ** Assume that t is too extreme to be represented in
1899 ** a struct tm; arrange things so that it is less
1900 ** extreme on the next pass.
1901 */
1902 dir = (t > 0) ? 1 : -1;
1903 } else dir = tmcomp(&mytm, &yourtm);
1904 if (dir != 0) {
1905 if (t == lo) {
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001906 if (t == TIME_T_MAX)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001907 return WRONG;
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001908 ++t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001909 ++lo;
1910 } else if (t == hi) {
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001911 if (t == TIME_T_MIN)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001912 return WRONG;
David 'Digit' Turner2093d352009-09-09 17:41:59 -07001913 --t;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001914 --hi;
1915 }
1916 if (lo > hi)
1917 return WRONG;
1918 if (dir > 0)
1919 hi = t;
1920 else lo = t;
1921 continue;
1922 }
1923 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1924 break;
1925 /*
1926 ** Right time, wrong type.
1927 ** Hunt for right time, right type.
1928 ** It's okay to guess wrong since the guess
1929 ** gets checked.
1930 */
1931 /*
1932 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1933 */
1934 sp = (const struct state *)
1935 (((void *) funcp == (void *) localsub) ?
1936 lclptr : gmtptr);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001937#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001938 if (sp == NULL)
1939 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001940#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001941 for (i = sp->typecnt - 1; i >= 0; --i) {
1942 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1943 continue;
1944 for (j = sp->typecnt - 1; j >= 0; --j) {
1945 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1946 continue;
1947 newt = t + sp->ttis[j].tt_gmtoff -
1948 sp->ttis[i].tt_gmtoff;
1949 if ((*funcp)(&newt, offset, &mytm) == NULL)
1950 continue;
1951 if (tmcomp(&mytm, &yourtm) != 0)
1952 continue;
1953 if (mytm.tm_isdst != yourtm.tm_isdst)
1954 continue;
1955 /*
1956 ** We have a match.
1957 */
1958 t = newt;
1959 goto label;
1960 }
1961 }
1962 return WRONG;
1963 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001964label:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001965 newt = t + saved_seconds;
1966 if ((newt < t) != (saved_seconds < 0))
1967 return WRONG;
1968 t = newt;
1969 if ((*funcp)(&t, offset, tmp))
1970 *okayp = TRUE;
1971 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001972}
1973
1974static time_t
1975time2(tmp, funcp, offset, okayp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001976struct tm * const tmp;
1977struct tm * (* const funcp) P((const time_t*, long, struct tm*));
1978const long offset;
1979int * const okayp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001980{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001981 time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001982
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001983 /*
1984 ** First try without normalization of seconds
1985 ** (in case tm_sec contains a value associated with a leap second).
1986 ** If that fails, try with normalization of seconds.
1987 */
1988 t = time2sub(tmp, funcp, offset, okayp, FALSE);
1989 return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001990}
1991
1992static time_t
1993time1(tmp, funcp, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001994struct tm * const tmp;
1995struct tm * (* const funcp) P((const time_t *, long, struct tm *));
1996const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001997{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001998 register time_t t;
1999 register const struct state * sp;
2000 register int samei, otheri;
2001 register int sameind, otherind;
2002 register int i;
2003 register int nseen;
2004 int seen[TZ_MAX_TYPES];
2005 int types[TZ_MAX_TYPES];
2006 int okay;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002007
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002008 if (tmp->tm_isdst > 1)
2009 tmp->tm_isdst = 1;
2010 t = time2(tmp, funcp, offset, &okay);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002011#ifdef PCTS
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002012 /*
2013 ** PCTS code courtesy Grant Sullivan.
2014 */
2015 if (okay)
2016 return t;
2017 if (tmp->tm_isdst < 0)
2018 tmp->tm_isdst = 0; /* reset to std and try again */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002019#endif /* defined PCTS */
2020#ifndef PCTS
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002021 if (okay || tmp->tm_isdst < 0)
2022 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002023#endif /* !defined PCTS */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002024 /*
2025 ** We're supposed to assume that somebody took a time of one type
2026 ** and did some math on it that yielded a "struct tm" that's bad.
2027 ** We try to divine the type they started from and adjust to the
2028 ** type they need.
2029 */
2030 /*
2031 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
2032 */
2033 sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
2034 lclptr : gmtptr);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002035#ifdef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002036 if (sp == NULL)
2037 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002038#endif /* defined ALL_STATE */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002039 for (i = 0; i < sp->typecnt; ++i)
2040 seen[i] = FALSE;
2041 nseen = 0;
2042 for (i = sp->timecnt - 1; i >= 0; --i)
2043 if (!seen[sp->types[i]]) {
2044 seen[sp->types[i]] = TRUE;
2045 types[nseen++] = sp->types[i];
2046 }
2047 for (sameind = 0; sameind < nseen; ++sameind) {
2048 samei = types[sameind];
2049 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2050 continue;
2051 for (otherind = 0; otherind < nseen; ++otherind) {
2052 otheri = types[otherind];
2053 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2054 continue;
2055 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
2056 sp->ttis[samei].tt_gmtoff;
2057 tmp->tm_isdst = !tmp->tm_isdst;
2058 t = time2(tmp, funcp, offset, &okay);
2059 if (okay)
2060 return t;
2061 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
2062 sp->ttis[samei].tt_gmtoff;
2063 tmp->tm_isdst = !tmp->tm_isdst;
2064 }
2065 }
2066 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002067}
2068
2069time_t
2070mktime(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002071struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002072{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002073 time_t result;
2074 _tzLock();
2075 tzset_locked();
2076 result = time1(tmp, localsub, 0L);
2077 _tzUnlock();
2078 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002079}
2080
2081#ifdef STD_INSPIRED
2082
2083time_t
2084timelocal(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002085struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002086{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002087 tmp->tm_isdst = -1; /* in case it wasn't initialized */
2088 return mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002089}
2090
2091time_t
2092timegm(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002093struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002094{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002095 time_t result;
2096
2097 tmp->tm_isdst = 0;
2098 _tzLock();
2099 result = time1(tmp, gmtsub, 0L);
2100 _tzUnlock();
2101
2102 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002103}
2104
2105time_t
2106timeoff(tmp, offset)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002107struct tm * const tmp;
2108const long offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002109{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002110 time_t result;
2111
2112 tmp->tm_isdst = 0;
2113 _tzLock();
2114 result = time1(tmp, gmtsub, offset);
2115 _tzUnlock();
2116
2117 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002118}
2119
2120#endif /* defined STD_INSPIRED */
2121
2122#ifdef CMUCS
2123
2124/*
2125** The following is supplied for compatibility with
2126** previous versions of the CMUCS runtime library.
2127*/
2128
2129long
2130gtime(tmp)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002131struct tm * const tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002132{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002133 const time_t t = mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002134
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002135 if (t == WRONG)
2136 return -1;
2137 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002138}
2139
2140#endif /* defined CMUCS */
2141
2142/*
2143** XXX--is the below the right way to conditionalize??
2144*/
2145
2146#ifdef STD_INSPIRED
2147
2148/*
2149** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2150** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2151** is not the case if we are accounting for leap seconds.
2152** So, we provide the following conversion routines for use
2153** when exchanging timestamps with POSIX conforming systems.
2154*/
2155
2156static long
2157leapcorr(timep)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002158time_t * timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002159{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002160 register struct state * sp;
2161 register struct lsinfo * lp;
2162 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002163
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002164 sp = lclptr;
2165 i = sp->leapcnt;
2166 while (--i >= 0) {
2167 lp = &sp->lsis[i];
2168 if (*timep >= lp->ls_trans)
2169 return lp->ls_corr;
2170 }
2171 return 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002172}
2173
2174time_t
2175time2posix(t)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002176time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002177{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002178 tzset();
2179 return t - leapcorr(&t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002180}
2181
2182time_t
2183posix2time(t)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002184time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002185{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002186 time_t x;
2187 time_t y;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002188
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07002189 tzset();
2190 /*
2191 ** For a positive leap second hit, the result
2192 ** is not unique. For a negative leap second
2193 ** hit, the corresponding time doesn't exist,
2194 ** so we return an adjacent second.
2195 */
2196 x = t + leapcorr(&t);
2197 y = x - leapcorr(&x);
2198 if (y < t) {
2199 do {
2200 x++;
2201 y = x - leapcorr(&x);
2202 } while (y < t);
2203 if (t != y)
2204 return x - 1;
2205 } else if (y > t) {
2206 do {
2207 --x;
2208 y = x - leapcorr(&x);
2209 } while (y > t);
2210 if (t != y)
2211 return x + 1;
2212 }
2213 return x;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002214}
2215
2216#endif /* defined STD_INSPIRED */