localtime.c 66.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson.
*/

/*
** Leap second handling from Bradley White.
** POSIX-style TZ environment variable handling from Guy Harris.
*/

/*LINTLIBRARY*/

#include "private.h"
#include "tzfile.h"
#include "fcntl.h"

#ifndef TZ_ABBR_MAX_LEN
18
#define TZ_ABBR_MAX_LEN 16
19 20 21 22
#endif /* !defined TZ_ABBR_MAX_LEN */

#ifndef TZ_ABBR_CHAR_SET
#define TZ_ABBR_CHAR_SET \
23
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
24 25 26
#endif /* !defined TZ_ABBR_CHAR_SET */

#ifndef TZ_ABBR_ERR_CHAR
27
#define TZ_ABBR_ERR_CHAR    '_'
28 29 30 31 32 33 34
#endif /* !defined TZ_ABBR_ERR_CHAR */

/*
** SunOS 4.1.1 headers lack O_BINARY.
*/

#ifdef O_BINARY
35
#define OPEN_MODE   (O_RDONLY | O_BINARY)
36 37
#endif /* defined O_BINARY */
#ifndef O_BINARY
38
#define OPEN_MODE   O_RDONLY
39 40 41 42 43 44 45 46
#endif /* !defined O_BINARY */

#if 0
#  define  XLOG(xx)  printf xx , fflush(stdout)
#else
#  define  XLOG(x)   do{}while (0)
#endif

Elliott Hughes's avatar
Elliott Hughes committed
47 48 49 50 51 52
/* BEGIN android-added: thread-safety. */
#include <pthread.h>
static pthread_mutex_t _tzMutex = PTHREAD_MUTEX_INITIALIZER;
static inline void _tzLock(void) { pthread_mutex_lock(&_tzMutex); }
static inline void _tzUnlock(void) { pthread_mutex_unlock(&_tzMutex); }
/* END android-added */
53

54 55 56
#ifndef WILDABBR
/*
** Someone might make incorrect use of a time zone abbreviation:
57 58 59 60 61 62 63 64 65
**  1.  They might reference tzname[0] before calling tzset (explicitly
**      or implicitly).
**  2.  They might reference tzname[1] before calling tzset (explicitly
**      or implicitly).
**  3.  They might reference tzname[1] after setting to a time zone
**      in which Daylight Saving Time is never observed.
**  4.  They might reference tzname[0] after setting to a time zone
**      in which Standard Time is never observed.
**  5.  They might reference tm.TM_ZONE after calling offtime.
66 67 68 69 70 71 72 73
** What's best to do in the above cases is open to debate;
** for now, we just set things up so that in any of the five cases
** WILDABBR is used. Another possibility: initialize tzname[0] to the
** string "tzname[0] used before set", and similarly for the other cases.
** And another: initialize tzname[0] to "ERA", with an explanation in the
** manual page of what this "time zone abbreviation" means (doing this so
** that tzname[0] has the "normal" length of three characters).
*/
74
#define WILDABBR    "   "
75 76
#endif /* !defined WILDABBR */

77
static char     wildabbr[] = WILDABBR;
78

79
static const char   gmt[] = "GMT";
80 81 82 83 84 85 86 87 88 89 90 91

/*
** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
** We default to US rules as of 1999-08-17.
** POSIX 1003.1 section 8.1.1 says that the default DST rules are
** implementation dependent; for historical reasons, US rules are a
** common default.
*/
#ifndef TZDEFRULESTRING
#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
#endif /* !defined TZDEFDST */

92
struct ttinfo {             /* time type information */
93
    int_fast32_t tt_gmtoff;  /* UT offset in seconds */
Elliott Hughes's avatar
Elliott Hughes committed
94 95 96
    int          tt_isdst;   /* used to set tm_isdst */
    int          tt_abbrind; /* abbreviation list index */
    int          tt_ttisstd; /* TRUE if transition is std time */
97
    int          tt_ttisgmt; /* TRUE if transition is UT */
98 99
};

100
struct lsinfo {             /* leap second information */
Elliott Hughes's avatar
Elliott Hughes committed
101 102
    time_t       ls_trans;   /* transition time */
    int_fast64_t ls_corr;    /* correction to apply */
103 104
};

105
#define BIGGEST(a, b)   (((a) > (b)) ? (a) : (b))
106 107

#ifdef TZNAME_MAX
108
#define MY_TZNAME_MAX   TZNAME_MAX
109 110
#endif /* defined TZNAME_MAX */
#ifndef TZNAME_MAX
111
#define MY_TZNAME_MAX   255
112 113 114
#endif /* !defined TZNAME_MAX */

struct state {
115 116 117 118 119 120 121 122 123 124 125 126
    int     leapcnt;
    int     timecnt;
    int     typecnt;
    int     charcnt;
    int     goback;
    int     goahead;
    time_t      ats[TZ_MAX_TIMES];
    unsigned char   types[TZ_MAX_TIMES];
    struct ttinfo   ttis[TZ_MAX_TYPES];
    char        chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
                (2 * (MY_TZNAME_MAX + 1)))];
    struct lsinfo   lsis[TZ_MAX_LEAPS];
Elliott Hughes's avatar
Elliott Hughes committed
127
    int defaulttype; /* for early times or if no transitions */
128 129 130
};

struct rule {
Elliott Hughes's avatar
Elliott Hughes committed
131 132 133 134 135
    int          r_type;     /* type of rule--see below */
    int          r_day;      /* day number of rule */
    int          r_week;     /* week number of rule */
    int          r_mon;      /* month number of rule */
    int_fast32_t r_time;     /* transition time of rule */
136 137
};

138 139 140
#define JULIAN_DAY      0   /* Jn - Julian day */
#define DAY_OF_YEAR     1   /* n - day of year */
#define MONTH_NTH_DAY_OF_WEEK   2   /* Mm.n.d - month, week, day of week */
141 142 143 144 145

/*
** Prototypes for static functions.
*/

146 147
/* NOTE: all internal functions assume that _tzLock() was already called */

148
static int __bionic_open_tzdata(const char*, int*);
Elliott Hughes's avatar
Elliott Hughes committed
149
static int_fast32_t detzcode(const char * codep);
Calin Juravle's avatar
Calin Juravle committed
150
static int_fast64_t	detzcode64(const char * codep);
Elliott Hughes's avatar
Elliott Hughes committed
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
static int      differ_by_repeat(time_t t1, time_t t0);
static const char * getzname(const char * strp) ATTRIBUTE_PURE;
static const char * getqzname(const char * strp, const int delim)
        ATTRIBUTE_PURE;
static const char * getnum(const char * strp, int * nump, int min,
                int max);
static const char * getsecs(const char * strp, int_fast32_t * secsp);
static const char * getoffset(const char * strp, int_fast32_t * offsetp);
static const char * getrule(const char * strp, struct rule * rulep);
static void     gmtload(struct state * sp);
static struct tm *  gmtsub(const time_t * timep, const int_fast32_t offset,
                struct tm * tmp, const struct state * sp); // android-changed: added sp.
static struct tm *  localsub(const time_t * timep, int_fast32_t offset,
                struct tm * tmp, const struct state * sp); // android-changed: added sp.
static int      increment_overflow(int * number, int delta);
static int      leaps_thru_end_of(int y) ATTRIBUTE_PURE;
static int      increment_overflow32(int_fast32_t * number, int delta);
Calin Juravle's avatar
Calin Juravle committed
168
static int		increment_overflow_time(time_t *t, int_fast32_t delta);
Elliott Hughes's avatar
Elliott Hughes committed
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
static int      normalize_overflow32(int_fast32_t * tensptr,
                int * unitsptr, int base);
static int      normalize_overflow(int * tensptr, int * unitsptr,
                int base);
static void     settzname(void);
static time_t       time1(struct tm * tmp,
                struct tm * (*funcp)(const time_t *,
                int_fast32_t, struct tm *, const struct state *), // android-changed: added state*.
                int_fast32_t offset, const struct state * sp); // android-changed: added sp.
static time_t       time2(struct tm * const tmp,
                struct tm * (*const funcp)(const time_t *,
                int_fast32_t, struct tm*, const struct state *), // android-changed: added state*.
                int_fast32_t offset, int * okayp, const struct state * sp); // android-changed: added sp.
static time_t       time2sub(struct tm *tmp,
                struct tm * (*funcp) (const time_t *,
                int_fast32_t, struct tm*, const struct state *), // android-changed: added state*.
                int_fast32_t offset, int * okayp, int do_norm_secs, const struct state * sp); // android-change: added sp.
static struct tm *  timesub(const time_t * timep, int_fast32_t offset,
                const struct state * sp, struct tm * tmp);
static int      tmcomp(const struct tm * atmp,
                const struct tm * btmp);
Calin Juravle's avatar
Calin Juravle committed
190 191
static int_fast32_t	transtime(int year, const struct rule * rulep,
				  int_fast32_t offset)
Elliott Hughes's avatar
Elliott Hughes committed
192 193 194 195 196 197
        ATTRIBUTE_PURE;
static int		typesequiv(const struct state * sp, int a, int b);
static int      tzload(const char * name, struct state * sp,
                int doextend);
static int      tzparse(const char * name, struct state * sp,
                int lastditch);
198 199

#ifdef ALL_STATE
200 201
static struct state *   lclptr;
static struct state *   gmtptr;
202 203 204
#endif /* defined ALL_STATE */

#ifndef ALL_STATE
205 206 207 208
static struct state lclmem;
static struct state gmtmem;
#define lclptr      (&lclmem)
#define gmtptr      (&gmtmem)
209 210 211 212 213 214
#endif /* State Farm */

#ifndef TZ_STRLEN_MAX
#define TZ_STRLEN_MAX 255
#endif /* !defined TZ_STRLEN_MAX */

215 216 217
static char     lcl_TZname[TZ_STRLEN_MAX + 1];
static int      lcl_is_set;
static int      gmt_is_set;
218

219 220 221
char *          tzname[2] = {
    wildabbr,
    wildabbr
222 223 224 225
};

/*
** Section 4.12.3 of X3.159-1989 requires that
226 227 228
**  Except for the strftime function, these functions [asctime,
**  ctime, gmtime, localtime] return values in one of two static
**  objects: a broken-down time structure and an array of char.
229 230 231
** Thanks to Paul Eggert for noting this.
*/

232
static struct tm    tmGlobal;
233 234

#ifdef USG_COMPAT
235 236
long			timezone = 0;
int			daylight = 0;
237 238 239
#endif /* defined USG_COMPAT */

#ifdef ALTZONE
240
long			altzone = 0;
241 242
#endif /* defined ALTZONE */

Elliott Hughes's avatar
Elliott Hughes committed
243 244
static int_fast32_t
detzcode(const char *const codep)
245
{
Elliott Hughes's avatar
Elliott Hughes committed
246 247
	register int_fast32_t	result;
	register int		i;
248

Elliott Hughes's avatar
Elliott Hughes committed
249 250 251 252
	result = (codep[0] & 0x80) ? -1 : 0;
	for (i = 0; i < 4; ++i)
		result = (result << 8) | (codep[i] & 0xff);
	return result;
253 254
}

Calin Juravle's avatar
Calin Juravle committed
255
static int_fast64_t
Elliott Hughes's avatar
Elliott Hughes committed
256
detzcode64(const char *const codep)
257
{
Calin Juravle's avatar
Calin Juravle committed
258
	register int_fast64_t result;
Elliott Hughes's avatar
Elliott Hughes committed
259
	register int	i;
260

Calin Juravle's avatar
Calin Juravle committed
261
	result = (codep[0] & 0x80) ? -1 : 0;
Elliott Hughes's avatar
Elliott Hughes committed
262
	for (i = 0; i < 8; ++i)
Calin Juravle's avatar
Calin Juravle committed
263
		result = (result << 8) | (codep[i] & 0xff);
Elliott Hughes's avatar
Elliott Hughes committed
264
	return result;
265 266 267
}

static void
Elliott Hughes's avatar
Elliott Hughes committed
268
settzname(void)
269
{
270 271
    register struct state * const   sp = lclptr;
    register int            i;
272

273 274
    tzname[0] = wildabbr;
    tzname[1] = wildabbr;
275
#ifdef USG_COMPAT
276 277
    daylight = 0;
    timezone = 0;
278 279
#endif /* defined USG_COMPAT */
#ifdef ALTZONE
280
    altzone = 0;
281 282
#endif /* defined ALTZONE */
#ifdef ALL_STATE
283 284 285 286
    if (sp == NULL) {
        tzname[0] = tzname[1] = gmt;
        return;
    }
287
#endif /* defined ALL_STATE */
Elliott Hughes's avatar
Elliott Hughes committed
288 289 290
    /*
    ** And to get the latest zone names into tzname. . .
    */
291 292
    for (i = 0; i < sp->typecnt; ++i) {
        register const struct ttinfo * const    ttisp = &sp->ttis[i];
293

Elliott Hughes's avatar
Elliott Hughes committed
294 295 296 297 298 299 300
        tzname[ttisp->tt_isdst] = &sp->chars[ttisp->tt_abbrind];
    }
    for (i = 0; i < sp->timecnt; ++i) {
        register const struct ttinfo * const    ttisp =
                            &sp->ttis[
                                sp->types[i]];

301 302
        tzname[ttisp->tt_isdst] =
            &sp->chars[ttisp->tt_abbrind];
303
#ifdef USG_COMPAT
304 305
        if (ttisp->tt_isdst)
            daylight = 1;
Elliott Hughes's avatar
Elliott Hughes committed
306
        if (!ttisp->tt_isdst)
307
            timezone = -(ttisp->tt_gmtoff);
308 309
#endif /* defined USG_COMPAT */
#ifdef ALTZONE
Elliott Hughes's avatar
Elliott Hughes committed
310
        if (ttisp->tt_isdst)
311
            altzone = -(ttisp->tt_gmtoff);
312
#endif /* defined ALTZONE */
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
    }
    /*
    ** Finally, scrub the abbreviations.
    ** First, replace bogus characters.
    */
    for (i = 0; i < sp->charcnt; ++i)
        if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
            sp->chars[i] = TZ_ABBR_ERR_CHAR;
    /*
    ** Second, truncate long abbreviations.
    */
    for (i = 0; i < sp->typecnt; ++i) {
        register const struct ttinfo * const    ttisp = &sp->ttis[i];
        register char *             cp = &sp->chars[ttisp->tt_abbrind];

        if (strlen(cp) > TZ_ABBR_MAX_LEN &&
            strcmp(cp, GRANDPARENTED) != 0)
                *(cp + TZ_ABBR_MAX_LEN) = '\0';
    }
332 333 334
}

static int
Elliott Hughes's avatar
Elliott Hughes committed
335
differ_by_repeat(const time_t t1, const time_t t0)
336
{
337
	if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
Elliott Hughes's avatar
Elliott Hughes committed
338
			return 0;
Elliott Hughes's avatar
Elliott Hughes committed
339
#if __LP64__ // 32-bit Android only has a signed 32-bit time_t; 64-bit Android is fixed.
Elliott Hughes's avatar
Elliott Hughes committed
340
	return t1 - t0 == SECSPERREPEAT;
Elliott Hughes's avatar
Elliott Hughes committed
341
#endif
342 343 344
}

static int
Elliott Hughes's avatar
Elliott Hughes committed
345 346
tzload(register const char* name, register struct state* const sp,
       register const int doextend)
347
{
348 349 350 351 352
    register const char *       p;
    register int            i;
    register int            fid;
    register int            stored;
    register int            nread;
Elliott Hughes's avatar
Elliott Hughes committed
353
    typedef union {
354 355 356 357
        struct tzhead   tzhead;
        char        buf[2 * sizeof(struct tzhead) +
                    2 * sizeof *sp +
                    4 * TZ_MAX_TIMES];
Elliott Hughes's avatar
Elliott Hughes committed
358 359 360
    } u_t;
#ifdef ALL_STATE
    register u_t *			up;
361

Elliott Hughes's avatar
Elliott Hughes committed
362 363 364 365 366 367 368 369 370 371 372 373 374
    up = (u_t *) calloc(1, sizeof *up);
    if (up == NULL)
        return -1;
#else /* !defined ALL_STATE */
    u_t				u;
    register u_t * const		up = &u;
#endif /* !defined ALL_STATE */

    sp->goback = sp->goahead = FALSE;
    if (name == NULL && (name = TZDEFAULT) == NULL)
        goto oops;
    int toread;
    fid = __bionic_open_tzdata(name, &toread);
375 376
    if (fid < 0)
        goto oops;
Elliott Hughes's avatar
Elliott Hughes committed
377 378 379
    nread = read(fid, up->buf, toread);
    if (close(fid) < 0 || nread <= 0)
        goto oops;
380 381 382
    for (stored = 4; stored <= 8; stored *= 2) {
        int     ttisstdcnt;
        int     ttisgmtcnt;
Calin Juravle's avatar
Calin Juravle committed
383
		int		timecnt;
384

Elliott Hughes's avatar
Elliott Hughes committed
385 386 387 388 389 390 391
        ttisstdcnt = (int) detzcode(up->tzhead.tzh_ttisstdcnt);
        ttisgmtcnt = (int) detzcode(up->tzhead.tzh_ttisgmtcnt);
        sp->leapcnt = (int) detzcode(up->tzhead.tzh_leapcnt);
        sp->timecnt = (int) detzcode(up->tzhead.tzh_timecnt);
        sp->typecnt = (int) detzcode(up->tzhead.tzh_typecnt);
        sp->charcnt = (int) detzcode(up->tzhead.tzh_charcnt);
        p = up->tzhead.tzh_charcnt + sizeof up->tzhead.tzh_charcnt;
392 393 394 395 396 397
        if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
            sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
            sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
            sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
            (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
            (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
Elliott Hughes's avatar
Elliott Hughes committed
398 399
                goto oops;
        if (nread - (p - up->buf) <
400 401 402 403 404 405 406
            sp->timecnt * stored +      /* ats */
            sp->timecnt +           /* types */
            sp->typecnt * 6 +       /* ttinfos */
            sp->charcnt +           /* chars */
            sp->leapcnt * (stored + 4) +    /* lsinfos */
            ttisstdcnt +            /* ttisstds */
            ttisgmtcnt)         /* ttisgmts */
Elliott Hughes's avatar
Elliott Hughes committed
407
                goto oops;
Calin Juravle's avatar
Calin Juravle committed
408
		timecnt = 0;
409
        for (i = 0; i < sp->timecnt; ++i) {
Calin Juravle's avatar
Calin Juravle committed
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
			int_fast64_t at
			  = stored == 4 ? detzcode(p) : detzcode64(p);
			sp->types[i] = ((TYPE_SIGNED(time_t)
					 ? time_t_min <= at
					 : 0 <= at)
					&& at <= time_t_max);
			if (sp->types[i]) {
				if (i && !timecnt && at != time_t_min) {
					/*
					** Keep the earlier record, but tweak
					** it so that it starts with the
					** minimum time_t value.
					*/
					sp->types[i - 1] = 1;
					sp->ats[timecnt++] = time_t_min;
				}
				sp->ats[timecnt++] = at;
			}
428 429
            p += stored;
        }
Calin Juravle's avatar
Calin Juravle committed
430
		timecnt = 0;
431
        for (i = 0; i < sp->timecnt; ++i) {
Calin Juravle's avatar
Calin Juravle committed
432 433
			unsigned char typ = *p++;
			if (sp->typecnt <= typ)
Elliott Hughes's avatar
Elliott Hughes committed
434
                goto oops;
Calin Juravle's avatar
Calin Juravle committed
435 436
			if (sp->types[i])
				sp->types[timecnt++] = typ;
437
        }
Calin Juravle's avatar
Calin Juravle committed
438
		sp->timecnt = timecnt;
439 440 441 442 443 444 445 446
        for (i = 0; i < sp->typecnt; ++i) {
            register struct ttinfo *    ttisp;

            ttisp = &sp->ttis[i];
            ttisp->tt_gmtoff = detzcode(p);
            p += 4;
            ttisp->tt_isdst = (unsigned char) *p++;
            if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
Elliott Hughes's avatar
Elliott Hughes committed
447
                goto oops;
448 449 450
            ttisp->tt_abbrind = (unsigned char) *p++;
            if (ttisp->tt_abbrind < 0 ||
                ttisp->tt_abbrind > sp->charcnt)
Elliott Hughes's avatar
Elliott Hughes committed
451
                    goto oops;
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
        }
        for (i = 0; i < sp->charcnt; ++i)
            sp->chars[i] = *p++;
        sp->chars[i] = '\0';    /* ensure '\0' at end */
        for (i = 0; i < sp->leapcnt; ++i) {
            register struct lsinfo *    lsisp;

            lsisp = &sp->lsis[i];
            lsisp->ls_trans = (stored == 4) ?
                detzcode(p) : detzcode64(p);
            p += stored;
            lsisp->ls_corr = detzcode(p);
            p += 4;
        }
        for (i = 0; i < sp->typecnt; ++i) {
            register struct ttinfo *    ttisp;

            ttisp = &sp->ttis[i];
            if (ttisstdcnt == 0)
                ttisp->tt_ttisstd = FALSE;
            else {
                ttisp->tt_ttisstd = *p++;
                if (ttisp->tt_ttisstd != TRUE &&
                    ttisp->tt_ttisstd != FALSE)
Elliott Hughes's avatar
Elliott Hughes committed
476
                        goto oops;
477
            }
478
        }
479 480 481 482 483 484 485 486 487 488
        for (i = 0; i < sp->typecnt; ++i) {
            register struct ttinfo *    ttisp;

            ttisp = &sp->ttis[i];
            if (ttisgmtcnt == 0)
                ttisp->tt_ttisgmt = FALSE;
            else {
                ttisp->tt_ttisgmt = *p++;
                if (ttisp->tt_ttisgmt != TRUE &&
                    ttisp->tt_ttisgmt != FALSE)
Elliott Hughes's avatar
Elliott Hughes committed
489
                        goto oops;
490 491 492 493 494
            }
        }
        /*
        ** If this is an old file, we're done.
        */
Elliott Hughes's avatar
Elliott Hughes committed
495
        if (up->tzhead.tzh_version[0] == '\0')
496
            break;
Elliott Hughes's avatar
Elliott Hughes committed
497
        nread -= p - up->buf;
498
        for (i = 0; i < nread; ++i)
Elliott Hughes's avatar
Elliott Hughes committed
499
            up->buf[i] = p[i];
500
        /*
Calin Juravle's avatar
Calin Juravle committed
501
		** If this is a signed narrow time_t system, we're done.
502
        */
Calin Juravle's avatar
Calin Juravle committed
503
		if (TYPE_SIGNED(time_t) && stored >= (int) sizeof(time_t))
504 505 506
            break;
    }
    if (doextend && nread > 2 &&
Elliott Hughes's avatar
Elliott Hughes committed
507
        up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
508 509 510 511
        sp->typecnt + 2 <= TZ_MAX_TYPES) {
            struct state    ts;
            register int    result;

Elliott Hughes's avatar
Elliott Hughes committed
512 513
            up->buf[nread - 1] = '\0';
            result = tzparse(&up->buf[1], &ts, FALSE);
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
            if (result == 0 && ts.typecnt == 2 &&
                sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
                    for (i = 0; i < 2; ++i)
                        ts.ttis[i].tt_abbrind +=
                            sp->charcnt;
                    for (i = 0; i < ts.charcnt; ++i)
                        sp->chars[sp->charcnt++] =
                            ts.chars[i];
                    i = 0;
                    while (i < ts.timecnt &&
                        ts.ats[i] <=
                        sp->ats[sp->timecnt - 1])
                            ++i;
                    while (i < ts.timecnt &&
                        sp->timecnt < TZ_MAX_TIMES) {
                        sp->ats[sp->timecnt] =
                            ts.ats[i];
                        sp->types[sp->timecnt] =
                            sp->typecnt +
                            ts.types[i];
                        ++sp->timecnt;
                        ++i;
                    }
                    sp->ttis[sp->typecnt++] = ts.ttis[0];
                    sp->ttis[sp->typecnt++] = ts.ttis[1];
            }
    }
Elliott Hughes's avatar
Elliott Hughes committed
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
    if (sp->timecnt > 1) {
        for (i = 1; i < sp->timecnt; ++i)
            if (typesequiv(sp, sp->types[i], sp->types[0]) &&
                    differ_by_repeat(sp->ats[i], sp->ats[0])) {
                sp->goback = TRUE;
                break;
            }
            for (i = sp->timecnt - 2; i >= 0; --i)
                if (typesequiv(sp, sp->types[sp->timecnt - 1],
                               sp->types[i]) &&
                        differ_by_repeat(sp->ats[sp->timecnt - 1],
                                         sp->ats[i])) {
                    sp->goahead = TRUE;
                    break;
            }
        }
        /*
        ** If type 0 is is unused in transitions,
        ** it's the type to use for early times.
        */
        for (i = 0; i < sp->typecnt; ++i)
            if (sp->types[i] == 0)
                break;
        i = (i >= sp->typecnt) ? 0 : -1;
        /*
        ** Absent the above,
        ** if there are transition times
        ** and the first transition is to a daylight time
        ** find the standard type less than and closest to
        ** the type of the first transition.
        */
        if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
            i = sp->types[0];
            while (--i >= 0)
                if (!sp->ttis[i].tt_isdst)
                    break;
        }
        /*
        ** If no result yet, find the first standard type.
        ** If there is none, punt to type zero.
        */
        if (i < 0) {
            i = 0;
            while (sp->ttis[i].tt_isdst)
                if (++i >= sp->typecnt) {
                    i = 0;
                    break;
                }
        }
        sp->defaulttype = i;
#ifdef ALL_STATE
        free(up);
#endif /* defined ALL_STATE */
        return 0;
oops:
#ifdef ALL_STATE
        free(up);
#endif /* defined ALL_STATE */
        return -1;
}

static int
typesequiv(const struct state *const sp, const int a, const int b)
{
	register int	result;

	if (sp == NULL ||
		a < 0 || a >= sp->typecnt ||
		b < 0 || b >= sp->typecnt)
			result = FALSE;
	else {
		register const struct ttinfo *	ap = &sp->ttis[a];
		register const struct ttinfo *	bp = &sp->ttis[b];
		result = ap->tt_gmtoff == bp->tt_gmtoff &&
			ap->tt_isdst == bp->tt_isdst &&
			ap->tt_ttisstd == bp->tt_ttisstd &&
			ap->tt_ttisgmt == bp->tt_ttisgmt &&
			strcmp(&sp->chars[ap->tt_abbrind],
			&sp->chars[bp->tt_abbrind]) == 0;
	}
	return result;
622 623
}

624 625 626
static const int    mon_lengths[2][MONSPERYEAR] = {
    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
627 628
};

629 630
static const int    year_lengths[2] = {
    DAYSPERNYEAR, DAYSPERLYEAR
631 632 633 634 635 636 637 638 639
};

/*
** Given a pointer into a time zone string, scan until a character that is not
** a valid character in a zone name is found. Return a pointer to that
** character.
*/

static const char *
Elliott Hughes's avatar
Elliott Hughes committed
640
getzname(register const char * strp)
641
{
642
    register char   c;
643

644 645 646 647
    while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
        c != '+')
            ++strp;
    return strp;
648 649 650 651 652 653 654 655 656 657 658 659 660 661
}

/*
** Given a pointer into an extended time zone string, scan until the ending
** delimiter of the zone name is located. Return a pointer to the delimiter.
**
** As with getzname above, the legal character set is actually quite
** restricted, with other characters producing undefined results.
** We don't do any checking here; checking is done later in common-case code.
*/

static const char *
getqzname(register const char *strp, const int delim)
{
662
    register int    c;
663

664 665 666
    while ((c = *strp) != '\0' && c != delim)
        ++strp;
    return strp;
667 668 669 670 671 672 673 674 675 676
}

/*
** Given a pointer into a time zone string, extract a number from that string.
** Check that the number is within a specified range; if it is not, return
** NULL.
** Otherwise, return a pointer to the first character not part of the number.
*/

static const char *
Elliott Hughes's avatar
Elliott Hughes committed
677
getnum(register const char * strp, int * const nump, const int min, const int max)
678
{
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
    register char   c;
    register int    num;

    if (strp == NULL || !is_digit(c = *strp))
        return NULL;
    num = 0;
    do {
        num = num * 10 + (c - '0');
        if (num > max)
            return NULL;    /* illegal value */
        c = *++strp;
    } while (is_digit(c));
    if (num < min)
        return NULL;        /* illegal value */
    *nump = num;
    return strp;
695 696 697 698 699 700 701 702 703 704 705
}

/*
** Given a pointer into a time zone string, extract a number of seconds,
** in hh[:mm[:ss]] form, from the string.
** If any error occurs, return NULL.
** Otherwise, return a pointer to the first character not part of the number
** of seconds.
*/

static const char *
Elliott Hughes's avatar
Elliott Hughes committed
706
getsecs(register const char *strp, int_fast32_t *const secsp)
707
{
708 709 710 711 712 713 714 715 716 717 718
    int num;

    /*
    ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
    ** "M10.4.6/26", which does not conform to Posix,
    ** but which specifies the equivalent of
    ** ``02:00 on the first Sunday on or after 23 Oct''.
    */
    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
    if (strp == NULL)
        return NULL;
Elliott Hughes's avatar
Elliott Hughes committed
719
    *secsp = num * (int_fast32_t) SECSPERHOUR;
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
    if (*strp == ':') {
        ++strp;
        strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
        if (strp == NULL)
            return NULL;
        *secsp += num * SECSPERMIN;
        if (*strp == ':') {
            ++strp;
            /* `SECSPERMIN' allows for leap seconds. */
            strp = getnum(strp, &num, 0, SECSPERMIN);
            if (strp == NULL)
                return NULL;
            *secsp += num;
        }
    }
    return strp;
736 737 738 739 740 741 742 743 744 745
}

/*
** Given a pointer into a time zone string, extract an offset, in
** [+-]hh[:mm[:ss]] form, from the string.
** If any error occurs, return NULL.
** Otherwise, return a pointer to the first character not part of the time.
*/

static const char *
Elliott Hughes's avatar
Elliott Hughes committed
746
getoffset(register const char *strp, int_fast32_t *const offsetp)
747
{
748 749 750 751 752 753 754 755 756 757 758 759 760
    register int    neg = 0;

    if (*strp == '-') {
        neg = 1;
        ++strp;
    } else if (*strp == '+')
        ++strp;
    strp = getsecs(strp, offsetp);
    if (strp == NULL)
        return NULL;        /* illegal time */
    if (neg)
        *offsetp = -*offsetp;
    return strp;
761 762 763 764 765 766 767 768 769 770
}

/*
** Given a pointer into a time zone string, extract a rule in the form
** date[/time]. See POSIX section 8 for the format of "date" and "time".
** If a valid rule is not found, return NULL.
** Otherwise, return a pointer to the first character not part of the rule.
*/

static const char *
Elliott Hughes's avatar
Elliott Hughes committed
771
getrule(const char * strp, register struct rule * const rulep)
772
{
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
    if (*strp == 'J') {
        /*
        ** Julian day.
        */
        rulep->r_type = JULIAN_DAY;
        ++strp;
        strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
    } else if (*strp == 'M') {
        /*
        ** Month, week, day.
        */
        rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
        ++strp;
        strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
        if (strp == NULL)
            return NULL;
        if (*strp++ != '.')
            return NULL;
        strp = getnum(strp, &rulep->r_week, 1, 5);
        if (strp == NULL)
            return NULL;
        if (*strp++ != '.')
            return NULL;
        strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
    } else if (is_digit(*strp)) {
        /*
        ** Day of year.
        */
        rulep->r_type = DAY_OF_YEAR;
        strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
    } else  return NULL;        /* invalid format */
    if (strp == NULL)
        return NULL;
    if (*strp == '/') {
        /*
        ** Time specified.
        */
        ++strp;
811
        strp = getoffset(strp, &rulep->r_time);
812 813
    } else  rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
    return strp;
814 815 816
}

/*
Calin Juravle's avatar
Calin Juravle committed
817 818
** Given a year, a rule, and the offset from UT at the time that rule takes
** effect, calculate the year-relative time that rule takes effect.
819 820
*/

Calin Juravle's avatar
Calin Juravle committed
821 822 823
static int_fast32_t
transtime(const int year, register const struct rule *const rulep,
	  const int_fast32_t offset)
824
{
825
    register int    leapyear;
Calin Juravle's avatar
Calin Juravle committed
826
	register int_fast32_t value;
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841
    register int    i;
    int     d, m1, yy0, yy1, yy2, dow;

    INITIALIZE(value);
    leapyear = isleap(year);
    switch (rulep->r_type) {

    case JULIAN_DAY:
        /*
        ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
        ** years.
        ** In non-leap years, or if the day number is 59 or less, just
        ** add SECSPERDAY times the day number-1 to the time of
        ** January 1, midnight, to get the day.
        */
Calin Juravle's avatar
Calin Juravle committed
842
		value = (rulep->r_day - 1) * SECSPERDAY;
843 844 845 846 847 848 849 850 851 852
        if (leapyear && rulep->r_day >= 60)
            value += SECSPERDAY;
        break;

    case DAY_OF_YEAR:
        /*
        ** n - day of year.
        ** Just add SECSPERDAY times the day number to the time of
        ** January 1, midnight, to get the day.
        */
Calin Juravle's avatar
Calin Juravle committed
853
		value = rulep->r_day * SECSPERDAY;
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
        break;

    case MONTH_NTH_DAY_OF_WEEK:
        /*
        ** Mm.n.d - nth "dth day" of month m.
        */

        /*
        ** Use Zeller's Congruence to get day-of-week of first day of
        ** month.
        */
        m1 = (rulep->r_mon + 9) % 12 + 1;
        yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
        yy1 = yy0 / 100;
        yy2 = yy0 % 100;
        dow = ((26 * m1 - 2) / 10 +
            1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
        if (dow < 0)
            dow += DAYSPERWEEK;

        /*
        ** "dow" is the day-of-week of the first day of the month. Get
        ** the day-of-month (zero-origin) of the first "dow" day of the
        ** month.
        */
        d = rulep->r_day - dow;
        if (d < 0)
            d += DAYSPERWEEK;
        for (i = 1; i < rulep->r_week; ++i) {
            if (d + DAYSPERWEEK >=
                mon_lengths[leapyear][rulep->r_mon - 1])
                    break;
            d += DAYSPERWEEK;
        }

        /*
        ** "d" is the day-of-month (zero-origin) of the day we want.
        */
Calin Juravle's avatar
Calin Juravle committed
892 893 894
		value = d * SECSPERDAY;
		for (i = 0; i < rulep->r_mon - 1; ++i)
			value += mon_lengths[leapyear][i] * SECSPERDAY;
895 896 897 898
        break;
    }

    /*
Calin Juravle's avatar
Calin Juravle committed
899 900
	** "value" is the year-relative time of 00:00:00 UT on the day in
	** question. To get the year-relative time of the specified local
901
    ** time on that day, add the transition time and the current offset
902
    ** from UT.
903 904
    */
    return value + rulep->r_time + offset;
905 906 907 908 909 910 911 912
}

/*
** Given a POSIX section 8-style TZ string, fill in the rule tables as
** appropriate.
*/

static int
Elliott Hughes's avatar
Elliott Hughes committed
913 914
tzparse(const char * name, register struct state * const sp,
        const int lastditch)
915
{
916 917 918 919
    const char *            stdname;
    const char *            dstname;
    size_t              stdlen;
    size_t              dstlen;
Elliott Hughes's avatar
Elliott Hughes committed
920 921
    int_fast32_t                stdoffset;
    int_fast32_t                dstoffset;
922 923
    register char *         cp;
    register int            load_result;
Elliott Hughes's avatar
Elliott Hughes committed
924
    static struct ttinfo    zttinfo;
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979

    INITIALIZE(dstname);
    stdname = name;
    if (lastditch) {
        stdlen = strlen(name);  /* length of standard zone name */
        name += stdlen;
        if (stdlen >= sizeof sp->chars)
            stdlen = (sizeof sp->chars) - 1;
        stdoffset = 0;
    } else {
        if (*name == '<') {
            name++;
            stdname = name;
            name = getqzname(name, '>');
            if (*name != '>')
                return (-1);
            stdlen = name - stdname;
            name++;
        } else {
            name = getzname(name);
            stdlen = name - stdname;
        }
        if (*name == '\0')
            return -1;
        name = getoffset(name, &stdoffset);
        if (name == NULL)
            return -1;
    }
    load_result = tzload(TZDEFRULES, sp, FALSE);
    if (load_result != 0)
        sp->leapcnt = 0;        /* so, we're off a little */
    if (*name != '\0') {
        if (*name == '<') {
            dstname = ++name;
            name = getqzname(name, '>');
            if (*name != '>')
                return -1;
            dstlen = name - dstname;
            name++;
        } else {
            dstname = name;
            name = getzname(name);
            dstlen = name - dstname; /* length of DST zone name */
        }
        if (*name != '\0' && *name != ',' && *name != ';') {
            name = getoffset(name, &dstoffset);
            if (name == NULL)
                return -1;
        } else  dstoffset = stdoffset - SECSPERHOUR;
        if (*name == '\0' && load_result != 0)
            name = TZDEFRULESTRING;
        if (*name == ',' || *name == ';') {
            struct rule start;
            struct rule end;
            register int    year;
980
            register int    yearlim;
Calin Juravle's avatar
Calin Juravle committed
981 982
			register int	timecnt;
			time_t		janfirst;
983 984 985 986 987 988 989 990 991 992 993 994 995 996

            ++name;
            if ((name = getrule(name, &start)) == NULL)
                return -1;
            if (*name++ != ',')
                return -1;
            if ((name = getrule(name, &end)) == NULL)
                return -1;
            if (*name != '\0')
                return -1;
            sp->typecnt = 2;    /* standard time and DST */
            /*
            ** Two transitions per year, from EPOCH_YEAR forward.
            */
Elliott Hughes's avatar
Elliott Hughes committed
997
            sp->ttis[0] = sp->ttis[1] = zttinfo;
998 999 1000 1001 1002 1003
            sp->ttis[0].tt_gmtoff = -dstoffset;
            sp->ttis[0].tt_isdst = 1;
            sp->ttis[0].tt_abbrind = stdlen + 1;
            sp->ttis[1].tt_gmtoff = -stdoffset;
            sp->ttis[1].tt_isdst = 0;
            sp->ttis[1].tt_abbrind = 0;
Calin Juravle's avatar
Calin Juravle committed
1004
			timecnt = 0;
1005
            janfirst = 0;
1006 1007
            yearlim = EPOCH_YEAR + YEARSPERREPEAT;
            for (year = EPOCH_YEAR; year < yearlim; year++) {
Calin Juravle's avatar
Calin Juravle committed
1008 1009 1010 1011
				int_fast32_t
				  starttime = transtime(year, &start, stdoffset),
				  endtime = transtime(year, &end, dstoffset);
				int_fast32_t
1012 1013
                yearsecs = (year_lengths[isleap(year)]
                            * SECSPERDAY);
Calin Juravle's avatar
Calin Juravle committed
1014 1015 1016 1017 1018 1019 1020
				int reversed = endtime < starttime;
				if (reversed) {
					int_fast32_t swap = starttime;
					starttime = endtime;
					endtime = swap;
				}
				if (reversed
1021 1022 1023 1024
                    || (starttime < endtime
                        && (endtime - starttime
                            < (yearsecs
                               + (stdoffset - dstoffset))))) {
Calin Juravle's avatar
Calin Juravle committed
1025
					if (TZ_MAX_TIMES - 2 < timecnt)
1026 1027
                        break;
                    yearlim = year + YEARSPERREPEAT + 1;
Calin Juravle's avatar
Calin Juravle committed
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
					sp->ats[timecnt] = janfirst;
					if (increment_overflow_time
					    (&sp->ats[timecnt], starttime))
						break;
					sp->types[timecnt++] = reversed;
					sp->ats[timecnt] = janfirst;
					if (increment_overflow_time
					    (&sp->ats[timecnt], endtime))
						break;
					sp->types[timecnt++] = !reversed;
1038
                    }
Calin Juravle's avatar
Calin Juravle committed
1039
				if (increment_overflow_time(&janfirst, yearsecs))
1040 1041
                    break;
            }
Calin Juravle's avatar
Calin Juravle committed
1042 1043
			sp->timecnt = timecnt;
			if (!timecnt)
1044
                sp->typecnt = 1;	/* Perpetual DST.  */
1045
        } else {
Elliott Hughes's avatar
Elliott Hughes committed
1046 1047 1048
            register int_fast32_t   theirstdoffset;
            register int_fast32_t   theirdstoffset;
            register int_fast32_t   theiroffset;
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
            register int    isdst;
            register int    i;
            register int    j;

            if (*name != '\0')
                return -1;
            /*
            ** Initial values of theirstdoffset and theirdstoffset.
            */
            theirstdoffset = 0;
            for (i = 0; i < sp->timecnt; ++i) {
                j = sp->types[i];
                if (!sp->ttis[j].tt_isdst) {
                    theirstdoffset =
                        -sp->ttis[j].tt_gmtoff;
                    break;
                }
            }
            theirdstoffset = 0;
            for (i = 0; i < sp->timecnt; ++i) {
                j = sp->types[i];
                if (sp->ttis[j].tt_isdst) {
                    theirdstoffset =
                        -sp->ttis[j].tt_gmtoff;
                    break;
                }
            }
            /*
            ** Initially we're assumed to be in standard time.
            */
            isdst = FALSE;
            theiroffset = theirstdoffset;
            /*
            ** Now juggle transition times and types
            ** tracking offsets as you do.
            */
            for (i = 0; i < sp->timecnt; ++i) {
                j = sp->types[i];
                sp->types[i] = sp->ttis[j].tt_isdst;
                if (sp->ttis[j].tt_ttisgmt) {
                    /* No adjustment to transition time */
                } else {
                    /*
                    ** If summer time is in effect, and the
                    ** transition time was not specified as
                    ** standard time, add the summer time
                    ** offset to the transition time;
                    ** otherwise, add the standard time
                    ** offset to the transition time.
                    */
                    /*
                    ** Transitions from DST to DDST
                    ** will effectively disappear since
                    ** POSIX provides for only one DST
                    ** offset.
                    */
                    if (isdst && !sp->ttis[j].tt_ttisstd) {
                        sp->ats[i] += dstoffset -
                            theirdstoffset;
                    } else {
                        sp->ats[i] += stdoffset -
                            theirstdoffset;
                    }
                }
                theiroffset = -sp->ttis[j].tt_gmtoff;
                if (sp->ttis[j].tt_isdst)
                    theirdstoffset = theiroffset;
                else    theirstdoffset = theiroffset;
            }
            /*
            ** Finally, fill in ttis.
            */
Elliott Hughes's avatar
Elliott Hughes committed
1121
            sp->ttis[0] = sp->ttis[1] = zttinfo;
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
            sp->ttis[0].tt_gmtoff = -stdoffset;
            sp->ttis[0].tt_isdst = FALSE;
            sp->ttis[0].tt_abbrind = 0;
            sp->ttis[1].tt_gmtoff = -dstoffset;
            sp->ttis[1].tt_isdst = TRUE;
            sp->ttis[1].tt_abbrind = stdlen + 1;
            sp->typecnt = 2;
        }
    } else {
        dstlen = 0;
        sp->typecnt = 1;        /* only standard time */
        sp->timecnt = 0;
Elliott Hughes's avatar
Elliott Hughes committed
1134
        sp->ttis[0] = zttinfo;
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
        sp->ttis[0].tt_gmtoff = -stdoffset;
        sp->ttis[0].tt_isdst = 0;
        sp->ttis[0].tt_abbrind = 0;
    }
    sp->charcnt = stdlen + 1;
    if (dstlen != 0)
        sp->charcnt += dstlen + 1;
    if ((size_t) sp->charcnt > sizeof sp->chars)
        return -1;
    cp = sp->chars;
    (void) strncpy(cp, stdname, stdlen);
    cp += stdlen;
    *cp++ = '\0';
    if (dstlen != 0) {
        (void) strncpy(cp, dstname, dstlen);
        *(cp + dstlen) = '\0';
    }
    return 0;
1153 1154 1155
}

static void
Elliott Hughes's avatar
Elliott Hughes committed
1156
gmtload(struct state * const sp)
1157
{
1158 1159
    if (tzload(gmt, sp, TRUE) != 0)
        (void) tzparse(gmt, sp, TRUE);
1160 1161
}

Elliott Hughes's avatar
Elliott Hughes committed
1162 1163 1164 1165 1166 1167 1168 1169 1170
#ifndef STD_INSPIRED
/*
** A non-static declaration of tzsetwall in a system header file
** may cause a warning about this upcoming static declaration...
*/
static
#endif /* !defined STD_INSPIRED */
void
tzsetwall(void)
1171
{
1172 1173 1174
    if (lcl_is_set < 0)
        return;
    lcl_is_set = -1;
1175 1176

#ifdef ALL_STATE
1177
    if (lclptr == NULL) {
Elliott Hughes's avatar
Elliott Hughes committed
1178
        lclptr = calloc(1, sizeof *lclptr);
1179 1180 1181 1182 1183
        if (lclptr == NULL) {
            settzname();    /* all we can do */
            return;
        }
    }
1184
#endif /* defined ALL_STATE */
Elliott Hughes's avatar
Elliott Hughes committed
1185
    if (tzload(NULL, lclptr, TRUE) != 0)
1186 1187
        gmtload(lclptr);
    settzname();
1188 1189
}

Elliott Hughes's avatar
Elliott Hughes committed
1190 1191
#include <sys/system_properties.h> // For __system_property_get.

1192
static void
Elliott Hughes's avatar
Elliott Hughes committed
1193
tzset_locked(void)
1194
{
1195
    register const char *   name = NULL;
1196

1197
    name = getenv("TZ");
1198

1199
    // try the "persist.sys.timezone" system property first
Elliott Hughes's avatar
Elliott Hughes committed
1200 1201
    static char buf[PROP_VALUE_MAX];
    if (name == NULL && __system_property_get("persist.sys.timezone", buf) > 0) {
1202
        name = buf;
Elliott Hughes's avatar
Elliott Hughes committed
1203
    }
1204

1205 1206 1207 1208
    if (name == NULL) {
        tzsetwall();
        return;
    }
1209

1210 1211 1212 1213 1214
    if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0)
        return;
    lcl_is_set = strlen(name) < sizeof lcl_TZname;
    if (lcl_is_set)
        (void) strcpy(lcl_TZname, name);
1215 1216

#ifdef ALL_STATE
1217
    if (lclptr == NULL) {
Elliott Hughes's avatar
Elliott Hughes committed
1218
        lclptr = calloc(1, sizeof *lclptr);
1219 1220 1221 1222 1223
        if (lclptr == NULL) {
            settzname();    /* all we can do */
            return;
        }
    }
1224
#endif /* defined ALL_STATE */
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
    if (*name == '\0') {
        /*
        ** User wants it fast rather than right.
        */
        lclptr->leapcnt = 0;        /* so, we're off a little */
        lclptr->timecnt = 0;
        lclptr->typecnt = 0;
        lclptr->ttis[0].tt_isdst = 0;
        lclptr->ttis[0].tt_gmtoff = 0;
        lclptr->ttis[0].tt_abbrind = 0;
        (void) strcpy(lclptr->chars, gmt);
    } else if (tzload(name, lclptr, TRUE) != 0)
        if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
            (void) gmtload(lclptr);
    settzname();
}

void
Elliott Hughes's avatar
Elliott Hughes committed
1243
tzset(void)
1244 1245 1246 1247
{
    _tzLock();
    tzset_locked();
    _tzUnlock();
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260
}

/*
** The easy way to behave "as if no library function calls" localtime
** is to not call it--so we drop its guts into "localsub", which can be
** freely called. (And no, the PANS doesn't require the above behavior--
** but it *is* desirable.)
**
** The unused offset argument is for the benefit of mktime variants.
*/

/*ARGSUSED*/
static struct tm *
Elliott Hughes's avatar
Elliott Hughes committed
1261 1262
localsub(const time_t * const timep, const int_fast32_t offset,
         struct tm * const tmp, const struct state * sp) // android-changed: added sp.
1263
{
1264 1265 1266 1267
    register const struct ttinfo *  ttisp;
    register int            i;
    register struct tm *        result;
    const time_t            t = *timep;
1268

1269 1270 1271 1272 1273
    // BEGIN android-changed: support user-supplied sp.
    if (sp == NULL) {
        sp = lclptr;
    }
    // END android-changed
1274
#ifdef ALL_STATE
1275
    if (sp == NULL)
1276
        return gmtsub(timep, offset, tmp, sp); // android-changed: added sp.
1277
#endif /* defined ALL_STATE */
1278 1279 1280 1281
    if ((sp->goback && t < sp->ats[0]) ||
        (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
            time_t          newt = t;
            register time_t     seconds;
1282
            register time_t     years;
1283 1284 1285 1286 1287

            if (t < sp->ats[0])
                seconds = sp->ats[0] - t;
            else    seconds = t - sp->ats[sp->timecnt - 1];
            --seconds;
1288 1289
            years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
            seconds = years * AVGSECSPERYEAR;
1290 1291 1292 1293 1294 1295
            if (t < sp->ats[0])
                newt += seconds;
            else    newt -= seconds;
            if (newt < sp->ats[0] ||
                newt > sp->ats[sp->timecnt - 1])
                    return NULL;    /* "cannot happen" */
1296
            result = localsub(&newt, offset, tmp, sp); // android-changed: added sp.
1297 1298 1299 1300 1301
            if (result == tmp) {
                register time_t newy;

                newy = tmp->tm_year;
                if (t < sp->ats[0])
1302 1303
                    newy -= years;
                else    newy += years;
1304 1305 1306 1307 1308 1309 1310
                tmp->tm_year = newy;
                if (tmp->tm_year != newy)
                    return NULL;
            }
            return result;
    }
    if (sp->timecnt == 0 || t < sp->ats[0]) {
Elliott Hughes's avatar
Elliott Hughes committed
1311
        i = sp->defaulttype;
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
    } else {
        register int    lo = 1;
        register int    hi = sp->timecnt;

        while (lo < hi) {
            register int    mid = (lo + hi) >> 1;

            if (t < sp->ats[mid])
                hi = mid;
            else    lo = mid + 1;
        }
        i = (int) sp->types[lo - 1];
    }
    ttisp = &sp->ttis[i];
    /*
    ** To get (wrong) behavior that's compatible with System V Release 2.0
    ** you'd replace the statement below with
    **  t += ttisp->tt_gmtoff;
    **  timesub(&t, 0L, sp, tmp);
    */
    result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
    tmp->tm_isdst = ttisp->tt_isdst;
    tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
1335
#ifdef TM_ZONE
1336
    tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
1337
#endif /* defined TM_ZONE */
1338
    return result;
1339 1340 1341
}

struct tm *
Elliott Hughes's avatar
Elliott Hughes committed
1342
localtime(const time_t * const timep)
1343
{
1344
    return localtime_r(timep, &tmGlobal);
1345 1346 1347 1348 1349 1350 1351
}

/*
** Re-entrant version of localtime.
*/

struct tm *
Elliott Hughes's avatar
Elliott Hughes committed
1352
localtime_r(const time_t * const timep, struct tm * tmp)
1353
{
1354 1355 1356 1357
    struct tm*  result;

    _tzLock();
    tzset_locked();
1358
    result = localsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
1359 1360 1361
    _tzUnlock();

    return result;
1362 1363 1364 1365 1366 1367 1368
}

/*
** gmtsub is to gmtime as localsub is to localtime.
*/

static struct tm *
Elliott Hughes's avatar
Elliott Hughes committed
1369 1370
gmtsub(const time_t * const timep, const int_fast32_t offset,
       struct tm *const tmp, const struct state * sp) // android-changed: added sp.
1371
{
1372
    register struct tm *    result;
1373

1374 1375
    (void) sp; // android-added: unused.

1376 1377
    if (!gmt_is_set) {
        gmt_is_set = TRUE;
1378
#ifdef ALL_STATE
Elliott Hughes's avatar
Elliott Hughes committed
1379
        gmtptr = calloc(1, sizeof *gmtptr);
1380
        if (gmtptr != NULL)
1381
#endif /* defined ALL_STATE */
1382 1383 1384
            gmtload(gmtptr);
    }
    result = timesub(timep, offset, gmtptr, tmp);
1385
#ifdef TM_ZONE
1386 1387
    /*
    ** Could get fancy here and deliver something such as
1388
    ** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
1389 1390 1391 1392 1393
    ** but this is no time for a treasure hunt.
    */
    if (offset != 0)
        tmp->TM_ZONE = wildabbr;
    else {
1394
#ifdef ALL_STATE
1395 1396 1397
        if (gmtptr == NULL)
            tmp->TM_ZONE = gmt;
        else    tmp->TM_ZONE = gmtptr->chars;
1398 1399
#endif /* defined ALL_STATE */
#ifndef ALL_STATE
1400
        tmp->TM_ZONE = gmtptr->chars;
1401
#endif /* State Farm */
1402
    }
1403
#endif /* defined TM_ZONE */
1404
    return result;
1405 1406 1407
}

struct tm *
Elliott Hughes's avatar
Elliott Hughes committed
1408
gmtime(const time_t * const timep)
1409
{
1410
    return gmtime_r(timep, &tmGlobal);
1411 1412 1413 1414 1415 1416 1417
}

/*
* Re-entrant version of gmtime.
*/

struct tm *
Elliott Hughes's avatar
Elliott Hughes committed
1418
gmtime_r(const time_t * const timep, struct tm * tmp)
1419
{
1420 1421 1422
    struct tm*  result;

    _tzLock();
1423
    result = gmtsub(timep, 0L, tmp, NULL); // android-changed: extra parameter.
1424 1425 1426
    _tzUnlock();

    return result;
1427 1428 1429 1430 1431 1432 1433 1434
}

/*
** Return the number of leap years through the end of the given year
** where, to make the math easy, the answer for year zero is defined as zero.
*/

static int
Elliott Hughes's avatar
Elliott Hughes committed
1435
leaps_thru_end_of(register const int y)
1436
{
1437 1438
    return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
        -(leaps_thru_end_of(-(y + 1)) + 1);
1439 1440 1441
}

static struct tm *
Elliott Hughes's avatar
Elliott Hughes committed
1442 1443 1444
timesub(const time_t *const timep, const int_fast32_t offset,
        register const struct state *const sp,
        register struct tm *const tmp)
1445
{
1446 1447 1448
    register const struct lsinfo *  lp;
    register time_t         tdays;
    register int            idays;  /* unsigned would be so 2003 */
Elliott Hughes's avatar
Elliott Hughes committed
1449
    register int_fast64_t           rem;
1450 1451
    int             y;
    register const int *        ip;
Elliott Hughes's avatar
Elliott Hughes committed
1452
    register int_fast64_t           corr;
1453 1454 1455 1456 1457
    register int            hit;
    register int            i;

    corr = 0;
    hit = 0;
1458
#ifdef ALL_STATE
1459
    i = (sp == NULL) ? 0 : sp->leapcnt;
1460 1461
#endif /* defined ALL_STATE */
#ifndef ALL_STATE
1462
    i = sp->leapcnt;
1463
#endif /* State Farm */
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
    while (--i >= 0) {
        lp = &sp->lsis[i];
        if (*timep >= lp->ls_trans) {
            if (*timep == lp->ls_trans) {
                hit = ((i == 0 && lp->ls_corr > 0) ||
                    lp->ls_corr > sp->lsis[i - 1].ls_corr);
                if (hit)
                    while (i > 0 &&
                        sp->lsis[i].ls_trans ==
                        sp->lsis[i - 1].ls_trans + 1 &&
                        sp->lsis[i].ls_corr ==
                        sp->lsis[i - 1].ls_corr + 1) {
                            ++hit;
                            --i;
                    }
            }
            corr = lp->ls_corr;
            break;
        }
    }
    y = EPOCH_YEAR;
    tdays = *timep / SECSPERDAY;
    rem = *timep - tdays * SECSPERDAY;
    while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
        int     newy;
        register time_t tdelta;
        register int    idelta;
        register int    leapdays;

        tdelta = tdays / DAYSPERLYEAR;
1494 1495 1496
        if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
               && tdelta <= INT_MAX))
                return NULL;
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509
        idelta = tdelta;
        if (idelta == 0)
            idelta = (tdays < 0) ? -1 : 1;
        newy = y;
        if (increment_overflow(&newy, idelta))
            return NULL;
        leapdays = leaps_thru_end_of(newy - 1) -
            leaps_thru_end_of(y - 1);
        tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
        tdays -= leapdays;
        y = newy;
    }
    {
Elliott Hughes's avatar
Elliott Hughes committed
1510
        register int_fast32_t   seconds;
1511

1512
        seconds = tdays * SECSPERDAY;
1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
        tdays = seconds / SECSPERDAY;
        rem += seconds - tdays * SECSPERDAY;
    }
    /*
    ** Given the range, we can now fearlessly cast...
    */
    idays = tdays;
    rem += offset - corr;
    while (rem < 0) {
        rem += SECSPERDAY;
        --idays;
    }
    while (rem >= SECSPERDAY) {
        rem -= SECSPERDAY;
        ++idays;
    }
    while (idays < 0) {
        if (increment_overflow(&y, -1))
            return NULL;
        idays += year_lengths[isleap(y)];
    }
    while (idays >= year_lengths[isleap(y)]) {
        idays -= year_lengths[isleap(y)];
        if (increment_overflow(&y, 1))
            return NULL;
    }
    tmp->tm_year = y;
    if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
        return NULL;
    tmp->tm_yday = idays;
    /*
    ** The "extra" mods below avoid overflow problems.
    */
    tmp->tm_wday = EPOCH_WDAY +
        ((y - EPOCH_YEAR) % DAYSPERWEEK) *
        (DAYSPERNYEAR % DAYSPERWEEK) +
        leaps_thru_end_of(y - 1) -
        leaps_thru_end_of(EPOCH_YEAR - 1) +
        idays;
    tmp->tm_wday %= DAYSPERWEEK;
    if (tmp->tm_wday < 0)
        tmp->tm_wday += DAYSPERWEEK;
    tmp->tm_hour = (int) (rem / SECSPERHOUR);
    rem %= SECSPERHOUR;
    tmp->tm_min = (int) (rem / SECSPERMIN);
    /*
    ** A positive leap second requires a special
    ** representation. This uses "... ??:59:60" et seq.
    */
    tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
    ip = mon_lengths[isleap(y)];
    for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
        idays -= ip[tmp->tm_mon];
    tmp->tm_mday = (int) (idays + 1);
    tmp->tm_isdst = 0;
1568
#ifdef TM_GMTOFF
1569
    tmp->TM_GMTOFF = offset;
1570
#endif /* defined TM_GMTOFF */
1571
    return tmp;
1572 1573 1574
}

char *
Elliott Hughes's avatar
Elliott Hughes committed
1575
ctime(const time_t * const timep)
1576 1577 1578
{
/*
** Section 4.12.3.2 of X3.159-1989 requires that
1579 1580 1581
**  The ctime function converts the calendar time pointed to by timer
**  to local time in the form of a string. It is equivalent to
**      asctime(localtime(timer))
1582
*/
1583
    return asctime(localtime(timep));
1584 1585 1586
}

char *
Elliott Hughes's avatar
Elliott Hughes committed
1587
ctime_r(const time_t * const timep, char * buf)
1588
{
1589
    struct tm   mytm;
1590

1591
    return asctime_r(localtime_r(timep, &mytm), buf);
1592 1593 1594 1595
}

/*
** Adapted from code provided by Robert Elz, who writes:
1596 1597 1598 1599 1600
**  The "best" way to do mktime I think is based on an idea of Bob
**  Kridle's (so its said...) from a long time ago.
**  It does a binary search of the time_t space. Since time_t's are
**  just 32 bits, its a max of 32 iterations (even at 64 bits it
**  would still be very reasonable).
1601 1602 1603
*/

#ifndef WRONG
1604
#define WRONG   (-1)
1605 1606 1607
#endif /* !defined WRONG */

/*
Elliott Hughes's avatar
Elliott Hughes committed
1608
** Normalize logic courtesy Paul Eggert.
1609 1610 1611
*/

static int
Elliott Hughes's avatar
Elliott Hughes committed
1612
increment_overflow(int *const ip, int j)
1613
{
Elliott Hughes's avatar
Elliott Hughes committed
1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625
	register int const	i = *ip;

	/*
	** If i >= 0 there can only be overflow if i + j > INT_MAX
	** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
	** If i < 0 there can only be overflow if i + j < INT_MIN
	** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
	*/
	if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
		return TRUE;
	*ip += j;
	return FALSE;
1626 1627 1628
}

static int
Elliott Hughes's avatar
Elliott Hughes committed
1629
increment_overflow32(int_fast32_t *const lp, int const m)
1630
{
Elliott Hughes's avatar
Elliott Hughes committed
1631
	register int_fast32_t const	l = *lp;
1632

Elliott Hughes's avatar
Elliott Hughes committed
1633 1634 1635 1636
	if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
		return TRUE;
	*lp += m;
	return FALSE;
1637 1638
}

Calin Juravle's avatar
Calin Juravle committed
1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
static int
increment_overflow_time(time_t *tp, int_fast32_t j)
{
	/*
	** This is like
	** 'if (! (time_t_min <= *tp + j && *tp + j <= time_t_max)) ...',
	** except that it does the right thing even if *tp + j would overflow.
	*/
	if (! (j < 0
	       ? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp)
	       : *tp <= time_t_max - j))
		return TRUE;
	*tp += j;
	return FALSE;
}

1655
static int
Elliott Hughes's avatar
Elliott Hughes committed
1656
normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
1657
{
Elliott Hughes's avatar
Elliott Hughes committed
1658
	register int	tensdelta;
1659

Elliott Hughes's avatar
Elliott Hughes committed
1660 1661 1662 1663 1664
	tensdelta = (*unitsptr >= 0) ?
		(*unitsptr / base) :
		(-1 - (-1 - *unitsptr) / base);
	*unitsptr -= tensdelta * base;
	return increment_overflow(tensptr, tensdelta);
1665 1666 1667
}

static int
Elliott Hughes's avatar
Elliott Hughes committed
1668 1669
normalize_overflow32(int_fast32_t *const tensptr, int *const unitsptr,
		     const int base)
1670
{
Elliott Hughes's avatar
Elliott Hughes committed
1671
	register int	tensdelta;
1672

Elliott Hughes's avatar
Elliott Hughes committed
1673 1674 1675 1676 1677
	tensdelta = (*unitsptr >= 0) ?
		(*unitsptr / base) :
		(-1 - (-1 - *unitsptr) / base);
	*unitsptr -= tensdelta * base;
	return increment_overflow32(tensptr, tensdelta);
1678 1679 1680
}

static int
Elliott Hughes's avatar
Elliott Hughes committed
1681 1682
tmcomp(register const struct tm * const atmp,
       register const struct tm * const btmp)
1683
{
1684 1685
    register int    result;

1686 1687 1688
    if (atmp->tm_year != btmp->tm_year)
        return atmp->tm_year < btmp->tm_year ? -1 : 1;
    if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1689 1690 1691 1692 1693
        (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
        (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
        (result = (atmp->tm_min - btmp->tm_min)) == 0)
            result = atmp->tm_sec - btmp->tm_sec;
    return result;
1694 1695 1696
}

static time_t
Elliott Hughes's avatar
Elliott Hughes committed
1697 1698 1699 1700 1701
time2sub(struct tm * const tmp,
         struct tm *(*const funcp)(const time_t*, int_fast32_t, struct tm*, const struct state*),
         const int_fast32_t offset,
         int * const okayp,
         const int do_norm_secs, const struct state * sp) // android-changed: added sp
1702
{
1703 1704 1705
    register int            dir;
    register int            i, j;
    register int            saved_seconds;
Elliott Hughes's avatar
Elliott Hughes committed
1706
    register int_fast32_t           li;
1707 1708
    register time_t         lo;
    register time_t         hi;
Elliott Hughes's avatar
Elliott Hughes committed
1709
    int_fast32_t                y;
1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725
    time_t              newt;
    time_t              t;
    struct tm           yourtm, mytm;

    *okayp = FALSE;
    yourtm = *tmp;
    if (do_norm_secs) {
        if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
            SECSPERMIN))
                return WRONG;
    }
    if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
        return WRONG;
    if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
        return WRONG;
    y = yourtm.tm_year;
Elliott Hughes's avatar
Elliott Hughes committed
1726
    if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
1727 1728 1729 1730 1731
        return WRONG;
    /*
    ** Turn y into an actual year number for now.
    ** It is converted back to an offset from TM_YEAR_BASE later.
    */
Elliott Hughes's avatar
Elliott Hughes committed
1732
    if (increment_overflow32(&y, TM_YEAR_BASE))
1733 1734
        return WRONG;
    while (yourtm.tm_mday <= 0) {
Elliott Hughes's avatar
Elliott Hughes committed
1735
        if (increment_overflow32(&y, -1))
1736 1737 1738 1739 1740 1741 1742
            return WRONG;
        li = y + (1 < yourtm.tm_mon);
        yourtm.tm_mday += year_lengths[isleap(li)];
    }
    while (yourtm.tm_mday > DAYSPERLYEAR) {
        li = y + (1 < yourtm.tm_mon);
        yourtm.tm_mday -= year_lengths[isleap(li)];
Elliott Hughes's avatar
Elliott Hughes committed
1743
        if (increment_overflow32(&y, 1))
1744 1745 1746 1747 1748 1749 1750 1751 1752
            return WRONG;
    }
    for ( ; ; ) {
        i = mon_lengths[isleap(y)][yourtm.tm_mon];
        if (yourtm.tm_mday <= i)
            break;
        yourtm.tm_mday -= i;
        if (++yourtm.tm_mon >= MONSPERYEAR) {
            yourtm.tm_mon = 0;
Elliott Hughes's avatar
Elliott Hughes committed
1753
            if (increment_overflow32(&y, 1))
1754 1755 1756
                return WRONG;
        }
    }
Elliott Hughes's avatar
Elliott Hughes committed
1757
    if (increment_overflow32(&y, -TM_YEAR_BASE))
1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798
        return WRONG;
    yourtm.tm_year = y;
    if (yourtm.tm_year != y)
        return WRONG;
    if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
        saved_seconds = 0;
    else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
        /*
        ** We can't set tm_sec to 0, because that might push the
        ** time below the minimum representable time.
        ** Set tm_sec to 59 instead.
        ** This assumes that the minimum representable time is
        ** not in the same minute that a leap second was deleted from,
        ** which is a safer assumption than using 58 would be.
        */
        if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
            return WRONG;
        saved_seconds = yourtm.tm_sec;
        yourtm.tm_sec = SECSPERMIN - 1;
    } else {
        saved_seconds = yourtm.tm_sec;
        yourtm.tm_sec = 0;
    }
    /*
    ** Do a binary search (this works whatever time_t's type is).
    */
    if (!TYPE_SIGNED(time_t)) {
        lo = 0;
        hi = lo - 1;
    } else {
        lo = 1;
        for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
            lo *= 2;
        hi = -(lo + 1);
    }
    for ( ; ; ) {
        t = lo / 2 + hi / 2;
        if (t < lo)
            t = lo;
        else if (t > hi)
            t = hi;
1799
        if ((*funcp)(&t, offset, &mytm, sp) == NULL) { // android-changed: added sp.
1800 1801 1802 1803 1804 1805 1806 1807 1808
            /*
            ** Assume that t is too extreme to be represented in
            ** a struct tm; arrange things so that it is less
            ** extreme on the next pass.
            */
            dir = (t > 0) ? 1 : -1;
        } else  dir = tmcomp(&mytm, &yourtm);
        if (dir != 0) {
            if (t == lo) {
1809
                if (t == time_t_max)
Elliott Hughes's avatar
Elliott Hughes committed
1810
                    return WRONG;
1811
                ++t;
1812 1813
                ++lo;
            } else if (t == hi) {
1814
                if (t == time_t_min)
Elliott Hughes's avatar
Elliott Hughes committed
1815
                    return WRONG;
1816
                --t;
1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833
                --hi;
            }
            if (lo > hi)
                return WRONG;
            if (dir > 0)
                hi = t;
            else    lo = t;
            continue;
        }
        if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
            break;
        /*
        ** Right time, wrong type.
        ** Hunt for right time, right type.
        ** It's okay to guess wrong since the guess
        ** gets checked.
        */
1834 1835 1836
        // BEGIN android-changed: support user-supplied sp
        if (sp == NULL) {
            sp = (const struct state *)
Elliott Hughes's avatar
Elliott Hughes committed
1837
                ((funcp == localsub) ? lclptr : gmtptr);
1838 1839
        }
        // END android-changed
1840
#ifdef ALL_STATE
1841 1842
        if (sp == NULL)
            return WRONG;
1843
#endif /* defined ALL_STATE */
1844 1845 1846 1847 1848 1849 1850 1851
        for (i = sp->typecnt - 1; i >= 0; --i) {
            if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
                continue;
            for (j = sp->typecnt - 1; j >= 0; --j) {
                if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
                    continue;
                newt = t + sp->ttis[j].tt_gmtoff -
                    sp->ttis[i].tt_gmtoff;
1852
                if ((*funcp)(&newt, offset, &mytm, sp) == NULL) // android-changed: added sp.
1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866
                    continue;
                if (tmcomp(&mytm, &yourtm) != 0)
                    continue;
                if (mytm.tm_isdst != yourtm.tm_isdst)
                    continue;
                /*
                ** We have a match.
                */
                t = newt;
                goto label;
            }
        }
        return WRONG;
    }
1867
label:
1868 1869 1870 1871
    newt = t + saved_seconds;
    if ((newt < t) != (saved_seconds < 0))
        return WRONG;
    t = newt;
1872
    if ((*funcp)(&t, offset, tmp, sp)) // android-changed: added sp.
1873 1874
        *okayp = TRUE;
    return t;
1875 1876 1877
}

static time_t
Elliott Hughes's avatar
Elliott Hughes committed
1878 1879 1880 1881
time2(struct tm * const tmp,
      struct tm * (*const funcp)(const time_t *, int_fast32_t, struct tm *, const struct state *), // android-changed: added sp.
      const int_fast32_t offset,
      int *const okayp, const struct state* sp) // android-changed: added sp.
1882
{
1883 1884 1885 1886 1887 1888 1889
    time_t  t;

    /*
    ** First try without normalization of seconds
    ** (in case tm_sec contains a value associated with a leap second).
    ** If that fails, try with normalization of seconds.
    */
1890 1891
    t = time2sub(tmp, funcp, offset, okayp, FALSE, sp);
    return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE, sp);
1892 1893 1894
}

static time_t
Elliott Hughes's avatar
Elliott Hughes committed
1895 1896 1897
time1(struct tm * const tmp,
      struct tm * (* const funcp) (const time_t *, int_fast32_t, struct tm *, const struct state *), // android-changed: added sp.
      const int_fast32_t offset, const struct state * sp) // android-changed: added sp.
1898
{
1899 1900 1901 1902 1903 1904 1905 1906 1907
    register time_t         t;
    register int            samei, otheri;
    register int            sameind, otherind;
    register int            i;
    register int            nseen;
    int             seen[TZ_MAX_TYPES];
    int             types[TZ_MAX_TYPES];
    int             okay;

Elliott Hughes's avatar
Elliott Hughes committed
1908 1909 1910 1911
    if (tmp == NULL) {
        errno = EINVAL;
        return WRONG;
    }
1912 1913
    if (tmp->tm_isdst > 1)
        tmp->tm_isdst = 1;
1914
    t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
1915
#ifdef PCTS
1916 1917 1918 1919 1920 1921 1922
    /*
    ** PCTS code courtesy Grant Sullivan.
    */
    if (okay)
        return t;
    if (tmp->tm_isdst < 0)
        tmp->tm_isdst = 0;  /* reset to std and try again */
1923 1924
#endif /* defined PCTS */
#ifndef PCTS
1925 1926
    if (okay || tmp->tm_isdst < 0)
        return t;
1927
#endif /* !defined PCTS */
1928 1929 1930 1931 1932 1933
    /*
    ** We're supposed to assume that somebody took a time of one type
    ** and did some math on it that yielded a "struct tm" that's bad.
    ** We try to divine the type they started from and adjust to the
    ** type they need.
    */
1934 1935
    // BEGIN android-changed: support user-supplied sp.
    if (sp == NULL) {
Elliott Hughes's avatar
Elliott Hughes committed
1936
        sp = (const struct state *) ((funcp == localsub) ?  lclptr : gmtptr);
1937 1938
    }
    // BEGIN android-changed
1939
#ifdef ALL_STATE
1940 1941
    if (sp == NULL)
        return WRONG;
1942
#endif /* defined ALL_STATE */
1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961
    for (i = 0; i < sp->typecnt; ++i)
        seen[i] = FALSE;
    nseen = 0;
    for (i = sp->timecnt - 1; i >= 0; --i)
        if (!seen[sp->types[i]]) {
            seen[sp->types[i]] = TRUE;
            types[nseen++] = sp->types[i];
        }
    for (sameind = 0; sameind < nseen; ++sameind) {
        samei = types[sameind];
        if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
            continue;
        for (otherind = 0; otherind < nseen; ++otherind) {
            otheri = types[otherind];
            if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
                continue;
            tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
                    sp->ttis[samei].tt_gmtoff;
            tmp->tm_isdst = !tmp->tm_isdst;
1962
            t = time2(tmp, funcp, offset, &okay, sp); // android-changed: added sp.
1963 1964 1965 1966 1967 1968 1969 1970
            if (okay)
                return t;
            tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
                    sp->ttis[samei].tt_gmtoff;
            tmp->tm_isdst = !tmp->tm_isdst;
        }
    }
    return WRONG;
1971 1972 1973
}

time_t
Elliott Hughes's avatar
Elliott Hughes committed
1974
mktime(struct tm * const tmp)
1975
{
1976 1977
    _tzLock();
    tzset_locked();
Elliott Hughes's avatar
Elliott Hughes committed
1978
    time_t result = time1(tmp, localsub, 0L, NULL); // android-changed: extra parameter.
1979 1980
    _tzUnlock();
    return result;
1981 1982 1983 1984 1985
}

#ifdef STD_INSPIRED

time_t
Elliott Hughes's avatar
Elliott Hughes committed
1986
timelocal(struct tm * const tmp)
1987
{
Elliott Hughes's avatar
Elliott Hughes committed
1988 1989
    if (tmp != NULL)
        tmp->tm_isdst = -1; /* in case it wasn't initialized */
1990
    return mktime(tmp);
1991 1992 1993
}

time_t
Elliott Hughes's avatar
Elliott Hughes committed
1994
timegm(struct tm * const tmp)
1995
{
1996 1997
    time_t  result;

Elliott Hughes's avatar
Elliott Hughes committed
1998 1999
    if (tmp != NULL)
        tmp->tm_isdst = 0;
2000
    _tzLock();
2001
    result = time1(tmp, gmtsub, 0L, NULL); // android-changed: extra parameter.
2002 2003 2004
    _tzUnlock();

    return result;
2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015
}

#endif /* defined STD_INSPIRED */

#ifdef CMUCS

/*
** The following is supplied for compatibility with
** previous versions of the CMUCS runtime library.
*/

2016
long
Elliott Hughes's avatar
Elliott Hughes committed
2017
gtime(struct tm * const tmp)
2018
{
2019
    const time_t    t = mktime(tmp);
2020

2021 2022 2023
    if (t == WRONG)
        return -1;
    return t;
2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
}

#endif /* defined CMUCS */

/*
** XXX--is the below the right way to conditionalize??
*/

#ifdef STD_INSPIRED

/*
** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
** is not the case if we are accounting for leap seconds.
** So, we provide the following conversion routines for use
** when exchanging timestamps with POSIX conforming systems.
*/

Elliott Hughes's avatar
Elliott Hughes committed
2042 2043
static int_fast64_t
leapcorr(time_t * timep)
2044
{
2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056
    register struct state *     sp;
    register struct lsinfo *    lp;
    register int            i;

    sp = lclptr;
    i = sp->leapcnt;
    while (--i >= 0) {
        lp = &sp->lsis[i];
        if (*timep >= lp->ls_trans)
            return lp->ls_corr;
    }
    return 0;
2057 2058 2059
}

time_t
Elliott Hughes's avatar
Elliott Hughes committed
2060
time2posix(time_t t)
2061
{
2062 2063
    tzset();
    return t - leapcorr(&t);
2064 2065 2066
}

time_t
Elliott Hughes's avatar
Elliott Hughes committed
2067
posix2time(time_t t)
2068
{
2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096
    time_t  x;
    time_t  y;

    tzset();
    /*
    ** For a positive leap second hit, the result
    ** is not unique. For a negative leap second
    ** hit, the corresponding time doesn't exist,
    ** so we return an adjacent second.
    */
    x = t + leapcorr(&t);
    y = x - leapcorr(&x);
    if (y < t) {
        do {
            x++;
            y = x - leapcorr(&x);
        } while (y < t);
        if (t != y)
            return x - 1;
    } else if (y > t) {
        do {
            --x;
            y = x - leapcorr(&x);
        } while (y > t);
        if (t != y)
            return x + 1;
    }
    return x;
2097 2098 2099
}

#endif /* defined STD_INSPIRED */
2100

Elliott Hughes's avatar
Elliott Hughes committed
2101 2102
// BEGIN android-added

2103
#include <assert.h>
2104
#include <stdint.h>
Elliott Hughes's avatar
Elliott Hughes committed
2105
#include <arpa/inet.h> // For ntohl(3).
2106

Elliott Hughes's avatar
Elliott Hughes committed
2107 2108 2109 2110
static int to_int(unsigned char* s) {
  return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
}

2111 2112 2113 2114 2115 2116 2117 2118 2119
static int __bionic_open_tzdata_path(const char* path_prefix_variable, const char* path_suffix,
                                     const char* olson_id, int* data_size) {
  const char* path_prefix = getenv(path_prefix_variable);
  if (path_prefix == NULL) {
    fprintf(stderr, "%s: %s not set!\n", __FUNCTION__, path_prefix_variable);
    return -1;
  }
  char path[PATH_MAX];
  snprintf(path, sizeof(path), "%s/%s", path_prefix, path_suffix);
2120
  int fd = TEMP_FAILURE_RETRY(open(path, OPEN_MODE));
2121
  if (fd == -1) {
2122 2123
    XLOG(("%s: could not open \"%s\": %s\n", __FUNCTION__, path, strerror(errno)));
    return -2; // Distinguish failure to find any data from failure to find a specific id.
2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135
  }

  // byte[12] tzdata_version  -- "tzdata2012f\0"
  // int index_offset
  // int data_offset
  // int zonetab_offset
  struct bionic_tzdata_header {
    char tzdata_version[12];
    int32_t index_offset;
    int32_t data_offset;
    int32_t zonetab_offset;
  } header;
2136 2137 2138 2139 2140
  memset(&header, 0, sizeof(header));
  ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header)));
  if (bytes_read != sizeof(header)) {
    fprintf(stderr, "%s: could not read header of \"%s\": %s\n",
            __FUNCTION__, path, (bytes_read == -1) ? strerror(errno) : "short read");
2141 2142 2143 2144 2145
    close(fd);
    return -1;
  }

  if (strncmp(header.tzdata_version, "tzdata", 6) != 0 || header.tzdata_version[11] != 0) {
2146 2147
    fprintf(stderr, "%s: bad magic in \"%s\": \"%.6s\"\n",
            __FUNCTION__, path, header.tzdata_version);
2148 2149 2150 2151 2152
    close(fd);
    return -1;
  }

#if 0
2153
  fprintf(stderr, "version: %s\n", header.tzdata_version);
2154 2155 2156 2157 2158 2159
  fprintf(stderr, "index_offset = %d\n", ntohl(header.index_offset));
  fprintf(stderr, "data_offset = %d\n", ntohl(header.data_offset));
  fprintf(stderr, "zonetab_offset = %d\n", ntohl(header.zonetab_offset));
#endif

  if (TEMP_FAILURE_RETRY(lseek(fd, ntohl(header.index_offset), SEEK_SET)) == -1) {
2160 2161
    fprintf(stderr, "%s: couldn't seek to index in \"%s\": %s\n",
            __FUNCTION__, path, strerror(errno));
2162 2163 2164 2165 2166 2167
    close(fd);
    return -1;
  }

  off_t specific_zone_offset = -1;

2168 2169
  static const size_t NAME_LENGTH = 40;
  unsigned char buf[NAME_LENGTH + 3 * sizeof(int32_t)];
2170 2171 2172 2173 2174 2175 2176

  size_t id_count = (ntohl(header.data_offset) - ntohl(header.index_offset)) / sizeof(buf);
  for (size_t i = 0; i < id_count; ++i) {
    if (TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf))) != (ssize_t) sizeof(buf)) {
      break;
    }

2177 2178 2179
    char this_id[NAME_LENGTH + 1];
    memcpy(this_id, buf, NAME_LENGTH);
    this_id[NAME_LENGTH] = '\0';
2180 2181

    if (strcmp(this_id, olson_id) == 0) {
Elliott Hughes's avatar
Elliott Hughes committed
2182 2183
      specific_zone_offset = to_int(buf + NAME_LENGTH) + ntohl(header.data_offset);
      *data_size = to_int(buf + NAME_LENGTH + sizeof(int32_t));
2184 2185 2186 2187 2188
      break;
    }
  }

  if (specific_zone_offset == -1) {
2189
    XLOG(("%s: couldn't find zone \"%s\"\n", __FUNCTION__, olson_id));
2190 2191 2192 2193 2194
    close(fd);
    return -1;
  }

  if (TEMP_FAILURE_RETRY(lseek(fd, specific_zone_offset, SEEK_SET)) == -1) {
2195 2196
    fprintf(stderr, "%s: could not seek to %ld in \"%s\": %s\n",
            __FUNCTION__, specific_zone_offset, path, strerror(errno));
2197 2198 2199 2200
    close(fd);
    return -1;
  }

2201 2202
  // TODO: check that there's TZ_MAGIC at this offset, so we can fall back to the other file if not.

2203 2204
  return fd;
}
2205 2206

static int __bionic_open_tzdata(const char* olson_id, int* data_size) {
2207
  int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/tzdata", olson_id, data_size);
2208
  if (fd < 0) {
2209
    fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata", olson_id, data_size);
2210
    if (fd == -2) {
2211 2212 2213
      // The first thing that 'recovery' does is try to format the current time. It doesn't have
      // any tzdata available, so we must not abort here --- doing so breaks the recovery image!
      fprintf(stderr, "%s: couldn't find any tzdata when looking for %s!\n", __FUNCTION__, olson_id);
2214 2215 2216 2217
    }
  }
  return fd;
}
Elliott Hughes's avatar
Elliott Hughes committed
2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267

// Caches the most recent timezone (http://b/8270865).
static int __bionic_tzload_cached(const char* name, struct state* const sp, const int doextend) {
  _tzLock();

  // Our single-item cache.
  static char* gCachedTimeZoneName;
  static struct state gCachedTimeZone;

  // Do we already have this timezone cached?
  if (gCachedTimeZoneName != NULL && strcmp(name, gCachedTimeZoneName) == 0) {
    *sp = gCachedTimeZone;
    _tzUnlock();
    return 0;
  }

  // Can we load it?
  int rc = tzload(name, sp, doextend);
  if (rc == 0) {
    // Update the cache.
    free(gCachedTimeZoneName);
    gCachedTimeZoneName = strdup(name);
    gCachedTimeZone = *sp;
  }

  _tzUnlock();
  return rc;
}

// Non-standard API: mktime(3) but with an explicit timezone parameter.
time_t mktime_tz(struct tm* const tmp, const char* tz) {
  struct state st;
  if (__bionic_tzload_cached(tz, &st, TRUE) != 0) {
    // TODO: not sure what's best here, but for now, we fall back to gmt.
    gmtload(&st);
  }
  return time1(tmp, localsub, 0L, &st);
}

// Non-standard API: localtime(3) but with an explicit timezone parameter.
void localtime_tz(const time_t* const timep, struct tm* tmp, const char* tz) {
  struct state st;
  if (__bionic_tzload_cached(tz, &st, TRUE) != 0) {
    // TODO: not sure what's best here, but for now, we fall back to gmt.
    gmtload(&st);
  }
  localsub(timep, 0L, tmp, &st);
}

// END android-added