localtime.c 62.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/*
** 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*/

13
#define LOCALTIME_IMPLEMENTATION
14
#include "private.h"
15

16 17 18
#include "tzfile.h"
#include "fcntl.h"

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
#if THREAD_SAFE
# include <pthread.h>
static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
static int lock(void) { return pthread_mutex_lock(&locallock); }
static void unlock(void) { pthread_mutex_unlock(&locallock); }
#else
static int lock(void) { return 0; }
static void unlock(void) { }
#endif

/* NETBSD_INSPIRED_EXTERN functions are exported to callers if
   NETBSD_INSPIRED is defined, and are private otherwise.  */
#if NETBSD_INSPIRED
# define NETBSD_INSPIRED_EXTERN
#else
# define NETBSD_INSPIRED_EXTERN static
#endif

37
#ifndef TZ_ABBR_MAX_LEN
38
#define TZ_ABBR_MAX_LEN 16
39 40 41 42
#endif /* !defined TZ_ABBR_MAX_LEN */

#ifndef TZ_ABBR_CHAR_SET
#define TZ_ABBR_CHAR_SET \
43
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
44 45 46
#endif /* !defined TZ_ABBR_CHAR_SET */

#ifndef TZ_ABBR_ERR_CHAR
47
#define TZ_ABBR_ERR_CHAR    '_'
48 49 50 51 52 53 54
#endif /* !defined TZ_ABBR_ERR_CHAR */

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

#ifdef O_BINARY
55
#define OPEN_MODE   (O_RDONLY | O_BINARY)
56 57
#endif /* defined O_BINARY */
#ifndef O_BINARY
58
#define OPEN_MODE   O_RDONLY
59 60 61 62 63
#endif /* !defined O_BINARY */

#ifndef WILDABBR
/*
** Someone might make incorrect use of a time zone abbreviation:
64 65 66 67 68 69 70 71 72
**  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.
73 74 75 76 77 78 79 80
** 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).
*/
81
#define WILDABBR    "   "
82 83
#endif /* !defined WILDABBR */

Elliott Hughes's avatar
Elliott Hughes committed
84
static const char       wildabbr[] = WILDABBR;
85

86
static const char gmt[] = "GMT";
87 88 89 90 91 92 93 94 95 96 97 98

/*
** 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 */

99
struct ttinfo {              /* time type information */
100
    int_fast32_t tt_gmtoff;  /* UT offset in seconds */
101
    bool         tt_isdst;   /* used to set tm_isdst */
Elliott Hughes's avatar
Elliott Hughes committed
102
    int          tt_abbrind; /* abbreviation list index */
103 104
    bool         tt_ttisstd; /* transition is std time */
    bool         tt_ttisgmt; /* transition is UT */
105 106
};

107
struct lsinfo {              /* leap second information */
Elliott Hughes's avatar
Elliott Hughes committed
108 109
    time_t       ls_trans;   /* transition time */
    int_fast64_t ls_corr;    /* correction to apply */
110 111
};

112
#define SMALLEST(a, b)	(((a) < (b)) ? (a) : (b))
113
#define BIGGEST(a, b)   (((a) > (b)) ? (a) : (b))
114 115

#ifdef TZNAME_MAX
116
#define MY_TZNAME_MAX   TZNAME_MAX
117 118
#endif /* defined TZNAME_MAX */
#ifndef TZNAME_MAX
119
#define MY_TZNAME_MAX   255
120 121 122
#endif /* !defined TZNAME_MAX */

struct state {
123 124 125 126
    int           leapcnt;
    int           timecnt;
    int           typecnt;
    int           charcnt;
127 128
    bool          goback;
    bool          goahead;
129 130 131 132 133 134 135
    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];
    int           defaulttype; /* for early times or if no transitions */
136 137
};

138 139 140 141 142 143
enum r_type {
  JULIAN_DAY,		/* Jn = Julian day */
  DAY_OF_YEAR,		/* n = day of year */
  MONTH_NTH_DAY_OF_WEEK	/* Mm.n.d = month, week, day of week */
};

144
struct rule {
145
	enum r_type	r_type;		/* type of rule */
146 147 148 149
    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 */
150 151
};

152 153 154 155 156 157 158 159 160
static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
			 struct tm *);
static bool increment_overflow(int *, int);
static bool increment_overflow_time(time_t *, int_fast32_t);
static bool normalize_overflow32(int_fast32_t *, int *, int);
static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
			  struct tm *);
static bool typesequiv(struct state const *, int, int);
static bool tzparse(char const *, struct state *, bool);
161 162

#ifdef ALL_STATE
163 164
static struct state * lclptr;
static struct state * gmtptr;
165 166 167
#endif /* defined ALL_STATE */

#ifndef ALL_STATE
168 169 170 171
static struct state lclmem;
static struct state gmtmem;
#define lclptr      (&lclmem)
#define gmtptr      (&gmtmem)
172 173 174 175 176 177
#endif /* State Farm */

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

178 179
static char lcl_TZname[TZ_STRLEN_MAX + 1];
static int  lcl_is_set;
180 181 182

/*
** Section 4.12.3 of X3.159-1989 requires that
183 184 185
**  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.
186 187 188
** Thanks to Paul Eggert for noting this.
*/

189
static struct tm	tm;
190

Elliott Hughes's avatar
Elliott Hughes committed
191 192 193 194 195
#if !HAVE_POSIX_DECLS
char *			tzname[2] = {
	(char *) wildabbr,
	(char *) wildabbr
};
196
#ifdef USG_COMPAT
197 198
long			timezone;
int			daylight;
Elliott Hughes's avatar
Elliott Hughes committed
199 200
# endif
#endif
201 202

#ifdef ALTZONE
203
long			altzone;
204 205
#endif /* defined ALTZONE */

206 207 208 209 210 211 212 213 214 215 216
/* Initialize *S to a value based on GMTOFF, ISDST, and ABBRIND.  */
static void
init_ttinfo(struct ttinfo *s, int_fast32_t gmtoff, bool isdst, int abbrind)
{
  s->tt_gmtoff = gmtoff;
  s->tt_isdst = isdst;
  s->tt_abbrind = abbrind;
  s->tt_ttisstd = false;
  s->tt_ttisgmt = false;
}

Elliott Hughes's avatar
Elliott Hughes committed
217 218
static int_fast32_t
detzcode(const char *const codep)
219
{
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
	register int_fast32_t	result;
	register int		i;
	int_fast32_t one = 1;
	int_fast32_t halfmaxval = one << (32 - 2);
	int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
	int_fast32_t minval = -1 - maxval;

	result = codep[0] & 0x7f;
	for (i = 1; i < 4; ++i)
		result = (result << 8) | (codep[i] & 0xff);

	if (codep[0] & 0x80) {
	  /* Do two's-complement negation even on non-two's-complement machines.
	     If the result would be minval - 1, return minval.  */
	  result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
	  result += minval;
	}
	return result;
238 239
}

Calin Juravle's avatar
Calin Juravle committed
240
static int_fast64_t
Elliott Hughes's avatar
Elliott Hughes committed
241
detzcode64(const char *const codep)
242
{
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
	register uint_fast64_t result;
	register int	i;
	int_fast64_t one = 1;
	int_fast64_t halfmaxval = one << (64 - 2);
	int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
	int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval;

	result = codep[0] & 0x7f;
	for (i = 1; i < 8; ++i)
		result = (result << 8) | (codep[i] & 0xff);

	if (codep[0] & 0x80) {
	  /* Do two's-complement negation even on non-two's-complement machines.
	     If the result would be minval - 1, return minval.  */
	  result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
	  result += minval;
	}
	return result;
}
262

263 264 265 266 267 268 269 270 271 272 273 274
static void
update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
{
  tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
#ifdef USG_COMPAT
  if (!ttisp->tt_isdst)
    timezone = - ttisp->tt_gmtoff;
#endif
#ifdef ALTZONE
  if (ttisp->tt_isdst)
    altzone = - ttisp->tt_gmtoff;
#endif
275 276 277
}

static void
Elliott Hughes's avatar
Elliott Hughes committed
278
settzname(void)
279
{
280 281
	register struct state * const	sp = lclptr;
	register int			i;
282

283
	tzname[0] = tzname[1] = (char *) wildabbr;
284
#ifdef USG_COMPAT
285 286
	daylight = 0;
	timezone = 0;
287 288
#endif /* defined USG_COMPAT */
#ifdef ALTZONE
289
	altzone = 0;
290
#endif /* defined ALTZONE */
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
	if (sp == NULL) {
		tzname[0] = tzname[1] = (char *) gmt;
		return;
	}
	/*
	** And to get the latest zone names into tzname. . .
	*/
	for (i = 0; i < sp->typecnt; ++i) {
		register const struct ttinfo * const	ttisp = &sp->ttis[i];
		update_tzname_etc(sp, ttisp);
	}
	for (i = 0; i < sp->timecnt; ++i) {
		register const struct ttinfo * const	ttisp =
							&sp->ttis[
								sp->types[i]];
		update_tzname_etc(sp, ttisp);
307
#ifdef USG_COMPAT
308 309
		if (ttisp->tt_isdst)
			daylight = 1;
310
#endif /* defined USG_COMPAT */
311 312
	}
}
313

314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
static void
scrub_abbrs(struct state *sp)
{
	int i;
	/*
	** 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';
	}
335 336
}

337 338
static bool
differ_by_repeat(const time_t t1, const time_t t0)
339
{
340 341
    if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
        return 0;
342
#if defined(__LP64__) // 32-bit Android/glibc has a signed 32-bit time_t; 64-bit doesn't.
343
    return t1 - t0 == SECSPERREPEAT;
Elliott Hughes's avatar
Elliott Hughes committed
344
#endif
345 346
}

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
/* Input buffer for data read from a compiled tz file.  */
union input_buffer {
  /* The first part of the buffer, interpreted as a header.  */
  struct tzhead tzhead;

  /* The entire buffer.  */
  char buf[2 * sizeof(struct tzhead) + 2 * sizeof (struct state)
	   + 4 * TZ_MAX_TIMES];
};

/* Local storage needed for 'tzloadbody'.  */
union local_storage {
  /* The file name to be opened.  */
  char fullname[FILENAME_MAX + 1];

  /* The results of analyzing the file's contents after it is opened.  */
  struct {
    /* The input buffer.  */
    union input_buffer u;

    /* A temporary state used for parsing a TZ string in the file.  */
    struct state st;
  } u;
};

Elliott Hughes's avatar
Elliott Hughes committed
372
static int __bionic_open_tzdata(const char*, int32_t*);
373 374 375 376

/* Load tz data from the file named NAME into *SP.  Read extended
   format if DOEXTEND.  Use *LSP for temporary storage.  Return 0 on
   success, an errno value on failure.  */
377
static int
378 379
tzloadbody(char const *name, struct state *sp, bool doextend,
	   union local_storage *lsp)
380
{
381 382 383 384
	register int			i;
	register int			fid;
	register int			stored;
	register ssize_t		nread;
385
#if !defined(__BIONIC__)
386 387 388 389 390
	register bool doaccess;
	register char *fullname = lsp->fullname;
#endif
	register union input_buffer *up = &lsp->u.u;
	register int tzheadsize = sizeof (struct tzhead);
Elliott Hughes's avatar
Elliott Hughes committed
391

392 393 394 395 396 397 398 399
	sp->goback = sp->goahead = false;

	if (! name) {
		name = TZDEFAULT;
		if (! name)
		  return EINVAL;
	}

400
#if defined(__BIONIC__)
Elliott Hughes's avatar
Elliott Hughes committed
401 402
	int32_t entry_length;
	fid = __bionic_open_tzdata(name, &entry_length);
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
#else
	if (name[0] == ':')
		++name;
	doaccess = name[0] == '/';
	if (!doaccess) {
		char const *p = TZDIR;
		if (! p)
		  return EINVAL;
		if (sizeof lsp->fullname - 1 <= strlen(p) + strlen(name))
		  return ENAMETOOLONG;
		strcpy(fullname, p);
		strcat(fullname, "/");
		strcat(fullname, name);
		/* Set doaccess if '.' (as in "../") shows up in name.  */
		if (strchr(name, '.'))
			doaccess = true;
		name = fullname;
	}
	if (doaccess && access(name, R_OK) != 0)
	  return errno;
	fid = open(name, OPEN_MODE);
#endif
	if (fid < 0)
	  return errno;

Elliott Hughes's avatar
Elliott Hughes committed
428
#if defined(__BIONIC__)
429
	nread = TEMP_FAILURE_RETRY(read(fid, up->buf, entry_length));
Elliott Hughes's avatar
Elliott Hughes committed
430
#else
431
	nread = read(fid, up->buf, sizeof up->buf);
Elliott Hughes's avatar
Elliott Hughes committed
432
#endif
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 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 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 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
	if (nread < tzheadsize) {
	  int err = nread < 0 ? errno : EINVAL;
	  close(fid);
	  return err;
	}
	if (close(fid) < 0)
	  return errno;
	for (stored = 4; stored <= 8; stored *= 2) {
		int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
		int_fast32_t ttisgmtcnt = detzcode(up->tzhead.tzh_ttisgmtcnt);
		int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
		int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
		int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
		int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
		char const *p = up->buf + tzheadsize;
		if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
		       && 0 < typecnt && typecnt < TZ_MAX_TYPES
		       && 0 <= timecnt && timecnt < TZ_MAX_TIMES
		       && 0 <= charcnt && charcnt < TZ_MAX_CHARS
		       && (ttisstdcnt == typecnt || ttisstdcnt == 0)
		       && (ttisgmtcnt == typecnt || ttisgmtcnt == 0)))
		  return EINVAL;
		if (nread
		    < (tzheadsize		/* struct tzhead */
		       + timecnt * stored	/* ats */
		       + timecnt		/* types */
		       + typecnt * 6		/* ttinfos */
		       + charcnt		/* chars */
		       + leapcnt * (stored + 4)	/* lsinfos */
		       + ttisstdcnt		/* ttisstds */
		       + ttisgmtcnt))		/* ttisgmts */
		  return EINVAL;
		sp->leapcnt = leapcnt;
		sp->timecnt = timecnt;
		sp->typecnt = typecnt;
		sp->charcnt = charcnt;

		/* Read transitions, discarding those out of time_t range.
		   But pretend the last transition before time_t_min
		   occurred at time_t_min.  */
		timecnt = 0;
		for (i = 0; i < sp->timecnt; ++i) {
			int_fast64_t at
			  = stored == 4 ? detzcode(p) : detzcode64(p);
			sp->types[i] = at <= time_t_max;
			if (sp->types[i]) {
			  time_t attime
			    = ((TYPE_SIGNED(time_t) ? at < time_t_min : at < 0)
			       ? time_t_min : at);
			  if (timecnt && attime <= sp->ats[timecnt - 1]) {
			    if (attime < sp->ats[timecnt - 1])
			      return EINVAL;
			    sp->types[i - 1] = 0;
			    timecnt--;
			  }
			  sp->ats[timecnt++] = attime;
			}
			p += stored;
		}

		timecnt = 0;
		for (i = 0; i < sp->timecnt; ++i) {
			unsigned char typ = *p++;
			if (sp->typecnt <= typ)
			  return EINVAL;
			if (sp->types[i])
				sp->types[timecnt++] = typ;
		}
		sp->timecnt = timecnt;
		for (i = 0; i < sp->typecnt; ++i) {
			register struct ttinfo *	ttisp;
			unsigned char isdst, abbrind;

			ttisp = &sp->ttis[i];
			ttisp->tt_gmtoff = detzcode(p);
			p += 4;
			isdst = *p++;
			if (! (isdst < 2))
			  return EINVAL;
			ttisp->tt_isdst = isdst;
			abbrind = *p++;
			if (! (abbrind < sp->charcnt))
			  return EINVAL;
			ttisp->tt_abbrind = abbrind;
		}
		for (i = 0; i < sp->charcnt; ++i)
			sp->chars[i] = *p++;
		sp->chars[i] = '\0';	/* ensure '\0' at end */

		/* Read leap seconds, discarding those out of time_t range.  */
		leapcnt = 0;
		for (i = 0; i < sp->leapcnt; ++i) {
		  int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
		  int_fast32_t corr = detzcode(p + stored);
		  p += stored + 4;
		  if (tr <= time_t_max) {
		    time_t trans
		      = ((TYPE_SIGNED(time_t) ? tr < time_t_min : tr < 0)
			 ? time_t_min : tr);
		    if (leapcnt && trans <= sp->lsis[leapcnt - 1].ls_trans) {
		      if (trans < sp->lsis[leapcnt - 1].ls_trans)
			return EINVAL;
		      leapcnt--;
		    }
		    sp->lsis[leapcnt].ls_trans = trans;
		    sp->lsis[leapcnt].ls_corr = corr;
		    leapcnt++;
		  }
		}
		sp->leapcnt = leapcnt;

		for (i = 0; i < sp->typecnt; ++i) {
			register struct ttinfo *	ttisp;

			ttisp = &sp->ttis[i];
			if (ttisstdcnt == 0)
				ttisp->tt_ttisstd = false;
			else {
				if (*p != true && *p != false)
				  return EINVAL;
				ttisp->tt_ttisstd = *p++;
			}
		}
		for (i = 0; i < sp->typecnt; ++i) {
			register struct ttinfo *	ttisp;

			ttisp = &sp->ttis[i];
			if (ttisgmtcnt == 0)
				ttisp->tt_ttisgmt = false;
			else {
				if (*p != true && *p != false)
						return EINVAL;
				ttisp->tt_ttisgmt = *p++;
			}
		}
		/*
		** If this is an old file, we're done.
		*/
		if (up->tzhead.tzh_version[0] == '\0')
			break;
		nread -= p - up->buf;
		memmove(up->buf, p, nread);
	}
	if (doextend && nread > 2 &&
		up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
		sp->typecnt + 2 <= TZ_MAX_TYPES) {
			struct state	*ts = &lsp->u.st;

			up->buf[nread - 1] = '\0';
			if (tzparse(&up->buf[1], ts, false)
			    && ts->typecnt == 2) {

			  /* Attempt to reuse existing abbreviations.
			     Without this, America/Anchorage would stop
			     working after 2037 when TZ_MAX_CHARS is 50, as
			     sp->charcnt equals 42 (for LMT CAT CAWT CAPT AHST
			     AHDT YST AKDT AKST) and ts->charcnt equals 10
			     (for AKST AKDT).  Reusing means sp->charcnt can
			     stay 42 in this example.  */
			  int gotabbr = 0;
			  int charcnt = sp->charcnt;
			  for (i = 0; i < 2; i++) {
			    char *tsabbr = ts->chars + ts->ttis[i].tt_abbrind;
			    int j;
			    for (j = 0; j < charcnt; j++)
			      if (strcmp(sp->chars + j, tsabbr) == 0) {
				ts->ttis[i].tt_abbrind = j;
				gotabbr++;
				break;
			      }
			    if (! (j < charcnt)) {
			      int tsabbrlen = strlen(tsabbr);
			      if (j + tsabbrlen < TZ_MAX_CHARS) {
				strcpy(sp->chars + j, tsabbr);
				charcnt = j + tsabbrlen + 1;
				ts->ttis[i].tt_abbrind = j;
				gotabbr++;
			      }
			    }
			  }
			  if (gotabbr == 2) {
			    sp->charcnt = charcnt;
			    for (i = 0; i < ts->timecnt; i++)
			      if (sp->ats[sp->timecnt - 1] < ts->ats[i])
				break;
			    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];
			  }
			}
	}
	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->timecnt; ++i)
		if (sp->types[i] == 0)
			break;
	i = i < sp->timecnt ? -1 : 0;
	/*
	** 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;
	return 0;
Elliott Hughes's avatar
Elliott Hughes committed
682 683
}

684 685
/* Load tz data from the file named NAME into *SP.  Read extended
   format if DOEXTEND.  Return 0 on success, an errno value on failure.  */
Elliott Hughes's avatar
Elliott Hughes committed
686
static int
687
tzload(char const *name, struct state *sp, bool doextend)
Elliott Hughes's avatar
Elliott Hughes committed
688
{
689 690 691 692 693 694 695 696 697 698 699 700 701
#ifdef ALL_STATE
  union local_storage *lsp = malloc(sizeof *lsp);
  if (!lsp)
    return errno;
  else {
    int err = tzloadbody(name, sp, doextend, lsp);
    free(lsp);
    return err;
  }
#else
  union local_storage ls;
  return tzloadbody(name, sp, doextend, &ls);
#endif
702 703
}

704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
static bool
typesequiv(const struct state *sp, int a, int b)
{
	register bool 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;
}

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 }
729 730
};

731 732
static const int	year_lengths[2] = {
	DAYSPERNYEAR, DAYSPERLYEAR
733 734 735 736 737 738 739 740
};

/*
** 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.
*/

741 742
static const char * ATTRIBUTE_PURE
getzname(register const char *strp)
743
{
744
	register char	c;
745

746 747 748 749
	while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
		c != '+')
			++strp;
	return strp;
750 751 752 753 754 755 756 757 758 759 760
}

/*
** 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.
*/

761
static const char * ATTRIBUTE_PURE
762 763
getqzname(register const char *strp, const int delim)
{
764
	register int	c;
765

766 767 768
	while ((c = *strp) != '\0' && c != delim)
		++strp;
	return strp;
769 770 771 772 773 774 775 776 777 778
}

/*
** 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 *
779
getnum(register const char *strp, int *const nump, const int min, const int max)
780
{
781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
	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;
797 798 799 800 801 802 803 804 805 806 807
}

/*
** 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
808
getsecs(register const char *strp, int_fast32_t *const secsp)
809
{
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
	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;
	*secsp = num * (int_fast32_t) SECSPERHOUR;
	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;
838 839 840 841 842 843 844 845 846 847
}

/*
** 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
848
getoffset(register const char *strp, int_fast32_t *const offsetp)
849
{
850 851 852 853 854 855 856 857 858 859 860 861 862
	register bool neg = false;

	if (*strp == '-') {
		neg = true;
		++strp;
	} else if (*strp == '+')
		++strp;
	strp = getsecs(strp, offsetp);
	if (strp == NULL)
		return NULL;		/* illegal time */
	if (neg)
		*offsetp = -*offsetp;
	return strp;
863 864 865 866 867 868 869 870 871 872
}

/*
** 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 *
873
getrule(const char *strp, register struct rule *const rulep)
874
{
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
	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;
		strp = getoffset(strp, &rulep->r_time);
	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
	return strp;
916 917 918
}

/*
Calin Juravle's avatar
Calin Juravle committed
919 920
** 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.
921 922
*/

923
static int_fast32_t ATTRIBUTE_PURE
Calin Juravle's avatar
Calin Juravle committed
924
transtime(const int year, register const struct rule *const rulep,
925
          const int_fast32_t offset)
926
{
927
    register bool         leapyear;
928 929 930
    register int_fast32_t value;
    register int          i;
    int d, m1, yy0, yy1, yy2, dow;
931 932 933 934 935 936 937 938 939 940 941 942 943

    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.
        */
944
        value = (rulep->r_day - 1) * SECSPERDAY;
945 946 947 948 949 950 951 952 953 954
        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.
        */
955
        value = rulep->r_day * SECSPERDAY;
956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993
        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.
        */
994 995 996
        value = d * SECSPERDAY;
        for (i = 0; i < rulep->r_mon - 1; ++i)
            value += mon_lengths[leapyear][i] * SECSPERDAY;
997 998 999 1000
        break;
    }

    /*
1001 1002
    ** "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
1003
    ** time on that day, add the transition time and the current offset
1004
    ** from UT.
1005 1006
    */
    return value + rulep->r_time + offset;
1007 1008 1009 1010 1011 1012 1013
}

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

1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 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 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
static bool
tzparse(const char *name, struct state *sp, bool lastditch)
{
	const char *			stdname;
	const char *			dstname;
	size_t				stdlen;
	size_t				dstlen;
	size_t				charcnt;
	int_fast32_t			stdoffset;
	int_fast32_t			dstoffset;
	register char *			cp;
	register bool			load_ok;

	stdname = name;
	if (lastditch) {
		stdlen = sizeof gmt - 1;
		name += stdlen;
		stdoffset = 0;
	} else {
		if (*name == '<') {
			name++;
			stdname = name;
			name = getqzname(name, '>');
			if (*name != '>')
			  return false;
			stdlen = name - stdname;
			name++;
		} else {
			name = getzname(name);
			stdlen = name - stdname;
		}
		if (!stdlen)
		  return false;
		name = getoffset(name, &stdoffset);
		if (name == NULL)
		  return false;
	}
	charcnt = stdlen + 1;
	if (sizeof sp->chars < charcnt)
	  return false;
	load_ok = tzload(TZDEFRULES, sp, false) == 0;
	if (!load_ok)
		sp->leapcnt = 0;		/* so, we're off a little */
	if (*name != '\0') {
		if (*name == '<') {
			dstname = ++name;
			name = getqzname(name, '>');
			if (*name != '>')
			  return false;
			dstlen = name - dstname;
			name++;
		} else {
			dstname = name;
			name = getzname(name);
			dstlen = name - dstname; /* length of DST zone name */
		}
		if (!dstlen)
		  return false;
		charcnt += dstlen + 1;
		if (sizeof sp->chars < charcnt)
		  return false;
		if (*name != '\0' && *name != ',' && *name != ';') {
			name = getoffset(name, &dstoffset);
			if (name == NULL)
			  return false;
		} else	dstoffset = stdoffset - SECSPERHOUR;
		if (*name == '\0' && !load_ok)
			name = TZDEFRULESTRING;
		if (*name == ',' || *name == ';') {
			struct rule	start;
			struct rule	end;
			register int	year;
			register int	yearlim;
			register int	timecnt;
			time_t		janfirst;

			++name;
			if ((name = getrule(name, &start)) == NULL)
			  return false;
			if (*name++ != ',')
			  return false;
			if ((name = getrule(name, &end)) == NULL)
			  return false;
			if (*name != '\0')
			  return false;
			sp->typecnt = 2;	/* standard time and DST */
			/*
			** Two transitions per year, from EPOCH_YEAR forward.
			*/
			init_ttinfo(&sp->ttis[0], -dstoffset, true, stdlen + 1);
			init_ttinfo(&sp->ttis[1], -stdoffset, false, 0);
			sp->defaulttype = 0;
			timecnt = 0;
			janfirst = 0;
			yearlim = EPOCH_YEAR + YEARSPERREPEAT;
			for (year = EPOCH_YEAR; year < yearlim; year++) {
				int_fast32_t
				  starttime = transtime(year, &start, stdoffset),
				  endtime = transtime(year, &end, dstoffset);
				int_fast32_t
				  yearsecs = (year_lengths[isleap(year)]
					      * SECSPERDAY);
				bool reversed = endtime < starttime;
				if (reversed) {
					int_fast32_t swap = starttime;
					starttime = endtime;
					endtime = swap;
				}
				if (reversed
				    || (starttime < endtime
					&& (endtime - starttime
					    < (yearsecs
					       + (stdoffset - dstoffset))))) {
					if (TZ_MAX_TIMES - 2 < timecnt)
						break;
					yearlim = year + YEARSPERREPEAT + 1;
					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;
				}
				if (increment_overflow_time(&janfirst, yearsecs))
					break;
			}
			sp->timecnt = timecnt;
			if (!timecnt)
				sp->typecnt = 1;	/* Perpetual DST.  */
		} else {
			register int_fast32_t	theirstdoffset;
			register int_fast32_t	theirdstoffset;
			register int_fast32_t	theiroffset;
			register bool		isdst;
			register int		i;
			register int		j;

			if (*name != '\0')
			  return false;
			/*
			** 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.
			*/
			init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
			init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
			sp->typecnt = 2;
			sp->defaulttype = 0;
		}
	} else {
		dstlen = 0;
		sp->typecnt = 1;		/* only standard time */
		sp->timecnt = 0;
		init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
		sp->defaulttype = 0;
	}
	sp->charcnt = charcnt;
	cp = sp->chars;
	memcpy(cp, stdname, stdlen);
	cp += stdlen;
	*cp++ = '\0';
	if (dstlen != 0) {
		memcpy(cp, dstname, dstlen);
		*(cp + dstlen) = '\0';
	}
	return true;
}

static void
gmtload(struct state *const sp)
{
	if (tzload(gmt, sp, true) != 0)
		tzparse(gmt, sp, true);
}

/* Initialize *SP to a value appropriate for the TZ setting NAME.
   Return 0 on success, an errno value on failure.  */
1256
static int
1257
zoneinit(struct state *sp, char const *name)
1258
{
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
  if (name && ! name[0]) {
    /*
    ** User wants it fast rather than right.
    */
    sp->leapcnt = 0;		/* so, we're off a little */
    sp->timecnt = 0;
    sp->typecnt = 0;
    sp->charcnt = 0;
    sp->goback = sp->goahead = false;
    init_ttinfo(&sp->ttis[0], 0, false, 0);
    strcpy(sp->chars, gmt);
    sp->defaulttype = 0;
1271
    return 0;
1272 1273 1274 1275 1276 1277 1278 1279
  } else {
    int err = tzload(name, sp, true);
    if (err != 0 && name && name[0] != ':' && tzparse(name, sp, false))
      err = 0;
    if (err == 0)
      scrub_abbrs(sp);
    return err;
  }
1280 1281 1282
}

static void
1283
tzsetlcl(char const *name)
1284
{
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
  struct state *sp = lclptr;
  int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
  if (lcl < 0
      ? lcl_is_set < 0
      : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
    return;
#ifdef ALL_STATE
  if (! sp)
    lclptr = sp = malloc(sizeof *lclptr);
#endif /* defined ALL_STATE */
  if (sp) {
    if (zoneinit(sp, name) != 0)
      zoneinit(sp, "");
    if (0 < lcl)
      strcpy(lcl_TZname, name);
  }
  settzname();
  lcl_is_set = lcl;
1303 1304
}

1305
#ifdef STD_INSPIRED
Elliott Hughes's avatar
Elliott Hughes committed
1306 1307
void
tzsetwall(void)
1308
{
1309 1310 1311 1312
  if (lock() != 0)
    return;
  tzsetlcl(NULL);
  unlock();
1313
}
1314
#endif
1315

1316
#if defined(__BIONIC__)
Mark Salyzyn's avatar
Mark Salyzyn committed
1317 1318
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h> // For __system_property_serial.
1319
#endif
Elliott Hughes's avatar
Elliott Hughes committed
1320

1321
static void
1322
tzset_unlocked(void)
1323
{
1324
#if defined(__BIONIC__)
1325
  // The TZ environment variable is meant to override the system-wide setting.
1326
  const char* name = getenv("TZ");
1327

1328
  // If that's not set, look at the "persist.sys.timezone" system property.
1329
  if (name == NULL) {
1330
    static const prop_info* pi;
Mark Salyzyn's avatar
Mark Salyzyn committed
1331

1332 1333
    if (!pi) {
      pi = __system_property_find("persist.sys.timezone");
Elliott Hughes's avatar
Elliott Hughes committed
1334
    }
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
    if (pi) {
      static char buf[PROP_VALUE_MAX];
      static uint32_t s = -1;
      static bool ok = false;
      uint32_t serial = __system_property_serial(pi);
      if (serial != s) {
        ok = __system_property_read(pi, 0, buf) > 0;
        s = serial;
      }
      if (ok) {
1345 1346 1347 1348 1349 1350 1351 1352 1353
        // POSIX and Java disagree about the sign in a timezone string. For POSIX, "GMT+3" means
        // "3 hours west/behind", but for Java it means "3 hours east/ahead". Since (a) Java is
        // the one that matches human expectations and (b) this system property is used directly
        // by Java, we flip the sign here to translate from Java to POSIX. http://b/25463955.
        if (buf[3] == '-') {
          buf[3] = '+';
        } else if (buf[3] == '+') {
          buf[3] = '-';
        }
1354 1355
        name = buf;
      }
1356
    }
1357 1358
  }

1359
  // If the system property is also not available (because you're running AOSP on a WiFi-only
1360 1361 1362
  // device, say), fall back to GMT.
  if (name == NULL) name = gmt;

1363 1364 1365 1366 1367
  tzsetlcl(name);
#else
  tzsetlcl(getenv("TZ"));
#endif
}
1368

1369 1370 1371 1372 1373 1374 1375 1376
void
tzset(void)
{
  if (lock() != 0)
    return;
  tzset_unlocked();
  unlock();
}
1377

1378 1379 1380 1381 1382 1383 1384
static void
gmtcheck(void)
{
  static bool gmt_is_set;
  if (lock() != 0)
    return;
  if (! gmt_is_set) {
1385
#ifdef ALL_STATE
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406
    gmtptr = malloc(sizeof *gmtptr);
#endif
    if (gmtptr)
      gmtload(gmtptr);
    gmt_is_set = true;
  }
  unlock();
}

#if NETBSD_INSPIRED

timezone_t
tzalloc(char const *name)
{
  timezone_t sp = malloc(sizeof *sp);
  if (sp) {
    int err = zoneinit(sp, name);
    if (err != 0) {
      free(sp);
      errno = err;
      return NULL;
1407
    }
1408 1409
  }
  return sp;
1410 1411 1412
}

void
1413
tzfree(timezone_t sp)
1414
{
1415
  free(sp);
1416 1417
}

1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429
/*
** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
** ctime_r are obsolescent and have potential security problems that
** ctime_rz would share.  Callers can instead use localtime_rz + strftime.
**
** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
** in zones with three or more time zone abbreviations.
** Callers can instead use localtime_rz + strftime.
*/

#endif

1430 1431
/*
** The easy way to behave "as if no library function calls" localtime
1432 1433
** 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,
1434 1435
** but it *is* desirable.)
**
1436 1437 1438 1439 1440 1441
** If successful and SETNAME is nonzero,
** set the applicable parts of tzname, timezone and altzone;
** however, it's OK to omit this step if the time zone is POSIX-compatible,
** since in that case tzset should have already done this step correctly.
** SETNAME's type is intfast32_t for compatibility with gmtsub,
** but it is actually a boolean and its value should be 0 or 1.
1442 1443 1444 1445
*/

/*ARGSUSED*/
static struct tm *
1446 1447
localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
	 struct tm *const tmp)
1448
{
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 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 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
	register const struct ttinfo *	ttisp;
	register int			i;
	register struct tm *		result;
	const time_t			t = *timep;

	if (sp == NULL) {
	  /* Don't bother to set tzname etc.; tzset has already done it.  */
	  return gmtsub(gmtptr, timep, 0, tmp);
	}
	if ((sp->goback && t < sp->ats[0]) ||
		(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
			time_t			newt = t;
			register time_t		seconds;
			register time_t		years;

			if (t < sp->ats[0])
				seconds = sp->ats[0] - t;
			else	seconds = t - sp->ats[sp->timecnt - 1];
			--seconds;
			years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
			seconds = years * AVGSECSPERYEAR;
			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" */
			result = localsub(sp, &newt, setname, tmp);
			if (result) {
				register int_fast64_t newy;

				newy = result->tm_year;
				if (t < sp->ats[0])
					newy -= years;
				else	newy += years;
				if (! (INT_MIN <= newy && newy <= INT_MAX))
					return NULL;
				result->tm_year = newy;
			}
			return result;
	}
	if (sp->timecnt == 0 || t < sp->ats[0]) {
		i = sp->defaulttype;
	} 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);
	if (result) {
	  result->tm_isdst = ttisp->tt_isdst;
1515
#ifdef TM_ZONE
1516
	  result->TM_ZONE = (char *) &sp->chars[ttisp->tt_abbrind];
1517
#endif /* defined TM_ZONE */
1518 1519 1520 1521
	  if (setname)
	    update_tzname_etc(sp, ttisp);
	}
	return result;
1522 1523
}

1524 1525
#if NETBSD_INSPIRED

1526
struct tm *
1527
localtime_rz(struct state *sp, time_t const *timep, struct tm *tmp)
1528
{
1529
  return localsub(sp, timep, 0, tmp);
1530 1531
}

1532
#endif
1533

1534 1535
static struct tm *
localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
1536
{
1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547
  int err = lock();
  if (err) {
    errno = err;
    return NULL;
  }
  if (setname || !lcl_is_set)
    tzset_unlocked();
  tmp = localsub(lclptr, timep, setname, tmp);
  unlock();
  return tmp;
}
1548

1549 1550 1551 1552 1553
struct tm *
localtime(const time_t *timep)
{
  return localtime_tzset(timep, &tm, true);
}
1554

1555 1556 1557 1558
struct tm *
localtime_r(const time_t *timep, struct tm *tmp)
{
  return localtime_tzset(timep, tmp, false);
1559 1560 1561 1562 1563 1564 1565
}

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

static struct tm *
1566 1567
gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset,
       struct tm *tmp)
1568
{
1569
	register struct tm *	result;
1570

1571
	result = timesub(timep, offset, gmtptr, tmp);
1572
#ifdef TM_ZONE
1573 1574 1575 1576 1577 1578 1579
	/*
	** Could get fancy here and deliver something such as
	** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
	** but this is no time for a treasure hunt.
	*/
	tmp->TM_ZONE = ((char *)
			(offset ? wildabbr : gmtptr ? gmtptr->chars : gmt));
1580
#endif /* defined TM_ZONE */
1581
	return result;
1582 1583 1584 1585 1586 1587 1588
}

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

struct tm *
1589
gmtime_r(const time_t *timep, struct tm *tmp)
1590
{
1591 1592 1593
  gmtcheck();
  return gmtsub(gmtptr, timep, 0, tmp);
}
1594

1595 1596 1597 1598
struct tm *
gmtime(const time_t *timep)
{
  return gmtime_r(timep, &tm);
1599 1600
}

Elliott Hughes's avatar
Elliott Hughes committed
1601 1602 1603
#ifdef STD_INSPIRED

struct tm *
1604
offtime(const time_t *timep, long offset)
Elliott Hughes's avatar
Elliott Hughes committed
1605
{
1606 1607
  gmtcheck();
  return gmtsub(gmtptr, timep, offset, &tm);
Elliott Hughes's avatar
Elliott Hughes committed
1608 1609 1610 1611
}

#endif /* defined STD_INSPIRED */

1612 1613 1614 1615 1616
/*
** 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.
*/

1617
static int ATTRIBUTE_PURE
Elliott Hughes's avatar
Elliott Hughes committed
1618
leaps_thru_end_of(register const int y)
1619
{
1620 1621
	return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
		-(leaps_thru_end_of(-(y + 1)) + 1);
1622 1623 1624
}

static struct tm *
1625 1626
timesub(const time_t *timep, int_fast32_t offset,
	const struct state *sp, struct tm *tmp)
1627
{
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737
	register const struct lsinfo *	lp;
	register time_t			tdays;
	register int			idays;	/* unsigned would be so 2003 */
	register int_fast64_t		rem;
	int				y;
	register const int *		ip;
	register int_fast64_t		corr;
	register bool			hit;
	register int			i;

	corr = 0;
	hit = false;
	i = (sp == NULL) ? 0 : sp->leapcnt;
	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 % SECSPERDAY;
	while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
		int		newy;
		register time_t	tdelta;
		register int	idelta;
		register int	leapdays;

		tdelta = tdays / DAYSPERLYEAR;
		if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
		       && tdelta <= INT_MAX))
		  goto out_of_range;
		idelta = tdelta;
		if (idelta == 0)
			idelta = (tdays < 0) ? -1 : 1;
		newy = y;
		if (increment_overflow(&newy, idelta))
		  goto out_of_range;
		leapdays = leaps_thru_end_of(newy - 1) -
			leaps_thru_end_of(y - 1);
		tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
		tdays -= leapdays;
		y = newy;
	}
	/*
	** 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))
		  goto out_of_range;
		idays += year_lengths[isleap(y)];
	}
	while (idays >= year_lengths[isleap(y)]) {
		idays -= year_lengths[isleap(y)];
		if (increment_overflow(&y, 1))
		  goto out_of_range;
	}
	tmp->tm_year = y;
	if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
	  goto out_of_range;
	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;
1738
#ifdef TM_GMTOFF
1739
	tmp->TM_GMTOFF = offset;
1740
#endif /* defined TM_GMTOFF */
1741 1742 1743 1744 1745
	return tmp;

 out_of_range:
	errno = EOVERFLOW;
	return NULL;
1746 1747 1748
}

char *
1749
ctime(const time_t *timep)
1750 1751 1752
{
/*
** Section 4.12.3.2 of X3.159-1989 requires that
1753 1754 1755
**	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))
1756
*/
1757 1758
  struct tm *tmp = localtime(timep);
  return tmp ? asctime(tmp) : NULL;
1759 1760 1761
}

char *
1762
ctime_r(const time_t *timep, char *buf)
1763
{
1764 1765 1766
  struct tm mytm;
  struct tm *tmp = localtime_r(timep, &mytm);
  return tmp ? asctime_r(tmp, buf) : NULL;
1767 1768 1769 1770
}

/*
** Adapted from code provided by Robert Elz, who writes:
1771 1772 1773 1774 1775
**	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).
1776 1777 1778
*/

#ifndef WRONG
1779
#define WRONG	(-1)
1780 1781 1782
#endif /* !defined WRONG */

/*
Elliott Hughes's avatar
Elliott Hughes committed
1783
** Normalize logic courtesy Paul Eggert.
1784 1785
*/

1786 1787
static bool
increment_overflow(int *ip, int j)
1788
{
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800
	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;
1801 1802
}

1803
static bool
Elliott Hughes's avatar
Elliott Hughes committed
1804
increment_overflow32(int_fast32_t *const lp, int const m)
1805
{
1806
	register int_fast32_t const	l = *lp;
1807

1808 1809 1810 1811
	if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
		return true;
	*lp += m;
	return false;
1812 1813
}

1814
static bool
Calin Juravle's avatar
Calin Juravle committed
1815 1816
increment_overflow_time(time_t *tp, int_fast32_t j)
{
1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827
	/*
	** 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;
Calin Juravle's avatar
Calin Juravle committed
1828 1829
}

1830
static bool
Elliott Hughes's avatar
Elliott Hughes committed
1831
normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
1832
{
1833
	register int	tensdelta;
1834

1835 1836 1837 1838 1839
	tensdelta = (*unitsptr >= 0) ?
		(*unitsptr / base) :
		(-1 - (-1 - *unitsptr) / base);
	*unitsptr -= tensdelta * base;
	return increment_overflow(tensptr, tensdelta);
1840 1841
}

1842 1843
static bool
normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
1844
{
1845
	register int	tensdelta;
1846

1847 1848 1849 1850 1851
	tensdelta = (*unitsptr >= 0) ?
		(*unitsptr / base) :
		(-1 - (-1 - *unitsptr) / base);
	*unitsptr -= tensdelta * base;
	return increment_overflow32(tensptr, tensdelta);
1852 1853 1854
}

static int
1855 1856
tmcomp(register const struct tm *const atmp,
       register const struct tm *const btmp)
1857
{
1858 1859 1860 1861 1862 1863 1864 1865 1866 1867
	register int	result;

	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 &&
		(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;
1868 1869 1870
}

static time_t
1871 1872 1873 1874 1875 1876 1877
time2sub(struct tm *const tmp,
	 struct tm *(*funcp)(struct state const *, time_t const *,
			     int_fast32_t, struct tm *),
	 struct state const *sp,
	 const int_fast32_t offset,
	 bool *okayp,
	 bool do_norm_secs)
1878
{
1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056
	register int			dir;
	register int			i, j;
	register int			saved_seconds;
	register int_fast32_t		li;
	register time_t			lo;
	register time_t			hi;
	int_fast32_t			y;
	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;
	if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
		return WRONG;
	/*
	** Turn y into an actual year number for now.
	** It is converted back to an offset from TM_YEAR_BASE later.
	*/
	if (increment_overflow32(&y, TM_YEAR_BASE))
		return WRONG;
	while (yourtm.tm_mday <= 0) {
		if (increment_overflow32(&y, -1))
			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)];
		if (increment_overflow32(&y, 1))
			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;
			if (increment_overflow32(&y, 1))
				return WRONG;
		}
	}
	if (increment_overflow32(&y, -TM_YEAR_BASE))
		return WRONG;
	if (! (INT_MIN <= y && y <= INT_MAX))
		return WRONG;
	yourtm.tm_year = y;
	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).
	*/
	lo = time_t_min;
	hi = time_t_max;
	for ( ; ; ) {
		t = lo / 2 + hi / 2;
		if (t < lo)
			t = lo;
		else if (t > hi)
			t = hi;
		if (! funcp(sp, &t, offset, &mytm)) {
			/*
			** 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) {
				if (t == time_t_max)
					return WRONG;
				++t;
				++lo;
			} else if (t == hi) {
				if (t == time_t_min)
					return WRONG;
				--t;
				--hi;
			}
			if (lo > hi)
				return WRONG;
			if (dir > 0)
				hi = t;
			else	lo = t;
			continue;
		}
#if defined TM_GMTOFF && ! UNINIT_TRAP
		if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
		    && (yourtm.TM_GMTOFF < 0
			? (-SECSPERDAY <= yourtm.TM_GMTOFF
			   && (mytm.TM_GMTOFF <=
			       (SMALLEST (INT_FAST32_MAX, LONG_MAX)
				+ yourtm.TM_GMTOFF)))
			: (yourtm.TM_GMTOFF <= SECSPERDAY
			   && ((BIGGEST (INT_FAST32_MIN, LONG_MIN)
				+ yourtm.TM_GMTOFF)
			       <= mytm.TM_GMTOFF)))) {
		  /* MYTM matches YOURTM except with the wrong UTC offset.
		     YOURTM.TM_GMTOFF is plausible, so try it instead.
		     It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
		     since the guess gets checked.  */
		  time_t altt = t;
		  int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
		  if (!increment_overflow_time(&altt, diff)) {
		    struct tm alttm;
		    if (funcp(sp, &altt, offset, &alttm)
			&& alttm.tm_isdst == mytm.tm_isdst
			&& alttm.TM_GMTOFF == yourtm.TM_GMTOFF
			&& tmcomp(&alttm, &yourtm) == 0) {
		      t = altt;
		      mytm = alttm;
		    }
		  }
		}
#endif
		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.
		*/
		if (sp == NULL)
			return WRONG;
		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;
				if (! funcp(sp, &newt, offset, &mytm))
					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;
	}
2057
label:
2058 2059 2060 2061 2062 2063 2064
	newt = t + saved_seconds;
	if ((newt < t) != (saved_seconds < 0))
		return WRONG;
	t = newt;
	if (funcp(sp, &t, offset, tmp))
		*okayp = true;
	return t;
2065 2066 2067
}

static time_t
2068 2069 2070 2071
time2(struct tm * const	tmp,
      struct tm *(*funcp)(struct state const *, time_t const *,
			  int_fast32_t, struct tm *),
      struct state const *sp,
Elliott Hughes's avatar
Elliott Hughes committed
2072
      const int_fast32_t offset,
2073
      bool *okayp)
2074
{
2075 2076 2077 2078 2079 2080 2081 2082 2083
	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.
	*/
	t = time2sub(tmp, funcp, sp, offset, okayp, false);
	return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true);
2084 2085 2086
}

static time_t
2087 2088 2089 2090 2091
time1(struct tm *const tmp,
      struct tm *(*funcp) (struct state const *, time_t const *,
			   int_fast32_t, struct tm *),
      struct state const *sp,
      const int_fast32_t offset)
2092
{
2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111
	register time_t			t;
	register int			samei, otheri;
	register int			sameind, otherind;
	register int			i;
	register int			nseen;
	char				seen[TZ_MAX_TYPES];
	unsigned char			types[TZ_MAX_TYPES];
	bool				okay;

	if (tmp == NULL) {
		errno = EINVAL;
		return WRONG;
	}
	if (tmp->tm_isdst > 1)
		tmp->tm_isdst = 1;
	t = time2(tmp, funcp, sp, offset, &okay);
	if (okay)
		return t;
	if (tmp->tm_isdst < 0)
Elliott Hughes's avatar
Elliott Hughes committed
2112
#ifdef PCTS
2113 2114 2115 2116
		/*
		** POSIX Conformance Test Suite code courtesy Grant Sullivan.
		*/
		tmp->tm_isdst = 0;	/* reset to std and try again */
Elliott Hughes's avatar
Elliott Hughes committed
2117
#else
2118
		return t;
2119
#endif /* !defined PCTS */
2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155
	/*
	** 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.
	*/
	if (sp == NULL)
		return WRONG;
	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;
			t = time2(tmp, funcp, sp, offset, &okay);
			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;
2156 2157
}

2158 2159
static time_t
mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
2160
{
2161 2162 2163 2164 2165 2166
  if (sp)
    return time1(tmp, localsub, sp, setname);
  else {
    gmtcheck();
    return time1(tmp, gmtsub, gmtptr, 0);
  }
2167 2168
}

2169
#if NETBSD_INSPIRED
2170 2171

time_t
2172
mktime_z(struct state *sp, struct tm *tmp)
2173
{
2174
  return mktime_tzname(sp, tmp, false);
2175 2176
}

2177 2178
#endif

2179
time_t
2180
mktime(struct tm *tmp)
2181
{
2182
#if defined(__BIONIC__)
Elliott Hughes's avatar
Elliott Hughes committed
2183 2184 2185
  int saved_errno = errno;
#endif

2186 2187 2188 2189 2190 2191 2192 2193 2194
  time_t t;
  int err = lock();
  if (err) {
    errno = err;
    return -1;
  }
  tzset_unlocked();
  t = mktime_tzname(lclptr, tmp, true);
  unlock();
Elliott Hughes's avatar
Elliott Hughes committed
2195

2196
#if defined(__BIONIC__)
Elliott Hughes's avatar
Elliott Hughes committed
2197 2198
  errno = (t == -1) ? EOVERFLOW : saved_errno;
#endif
2199 2200
  return t;
}
2201

2202
#ifdef STD_INSPIRED
2203

2204 2205 2206 2207 2208 2209
time_t
timelocal(struct tm *tmp)
{
	if (tmp != NULL)
		tmp->tm_isdst = -1;	/* in case it wasn't initialized */
	return mktime(tmp);
2210 2211
}

Elliott Hughes's avatar
Elliott Hughes committed
2212
time_t
2213
timegm(struct tm *tmp)
Elliott Hughes's avatar
Elliott Hughes committed
2214
{
2215
  return timeoff(tmp, 0);
Elliott Hughes's avatar
Elliott Hughes committed
2216 2217
}

2218 2219
time_t
timeoff(struct tm *tmp, long offset)
2220
{
2221 2222 2223 2224
  if (tmp)
    tmp->tm_isdst = 0;
  gmtcheck();
  return time1(tmp, gmtsub, gmtptr, offset);
2225 2226
}

2227
#endif /* defined STD_INSPIRED */
2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242

/*
** 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
2243
static int_fast64_t
2244
leapcorr(struct state const *sp, time_t t)
2245
{
2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261
	register struct lsinfo const *	lp;
	register int			i;

	i = sp->leapcnt;
	while (--i >= 0) {
		lp = &sp->lsis[i];
		if (t >= lp->ls_trans)
			return lp->ls_corr;
	}
	return 0;
}

NETBSD_INSPIRED_EXTERN time_t ATTRIBUTE_PURE
time2posix_z(struct state *sp, time_t t)
{
  return t - leapcorr(sp, t);
2262 2263 2264
}

time_t
Elliott Hughes's avatar
Elliott Hughes committed
2265
time2posix(time_t t)
2266
{
2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306
  int err = lock();
  if (err) {
    errno = err;
    return -1;
  }
  if (!lcl_is_set)
    tzset_unlocked();
  if (lclptr)
    t = time2posix_z(lclptr, t);
  unlock();
  return t;
}

NETBSD_INSPIRED_EXTERN time_t ATTRIBUTE_PURE
posix2time_z(struct state *sp, time_t t)
{
	time_t	x;
	time_t	y;
	/*
	** 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(sp, t);
	y = x - leapcorr(sp, x);
	if (y < t) {
		do {
			x++;
			y = x - leapcorr(sp, x);
		} while (y < t);
		x -= y != t;
	} else if (y > t) {
		do {
			--x;
			y = x - leapcorr(sp, x);
		} while (y > t);
		x += y != t;
	}
	return x;
2307 2308 2309
}

time_t
Elliott Hughes's avatar
Elliott Hughes committed
2310
posix2time(time_t t)
2311
{
2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322
  int err = lock();
  if (err) {
    errno = err;
    return -1;
  }
  if (!lcl_is_set)
    tzset_unlocked();
  if (lclptr)
    t = posix2time_z(lclptr, t);
  unlock();
  return t;
2323 2324 2325
}

#endif /* defined STD_INSPIRED */
2326

2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342
#ifdef time_tz

/* Convert from the underlying system's time_t to the ersatz time_tz,
   which is called 'time_t' in this file.  */

time_t
time(time_t *p)
{
  time_t r = sys_time(0);
  if (p)
    *p = r;
  return r;
}

#endif

Elliott Hughes's avatar
Elliott Hughes committed
2343 2344
// BEGIN android-added

2345
#include <assert.h>
2346
#include <stdint.h>
Elliott Hughes's avatar
Elliott Hughes committed
2347
#include <arpa/inet.h> // For ntohl(3).
2348

2349
static int __bionic_open_tzdata_path(const char* path_prefix_variable, const char* path_suffix,
Elliott Hughes's avatar
Elliott Hughes committed
2350 2351
                                     const char* olson_id,
                                     int32_t* entry_length) {
2352 2353 2354 2355 2356
  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;
  }
2357 2358 2359 2360 2361 2362 2363
  size_t path_length = strlen(path_prefix) + 1 + strlen(path_suffix) + 1;
  char* path = malloc(path_length);
  if (path == NULL) {
    fprintf(stderr, "%s: couldn't allocate %zu-byte path\n", __FUNCTION__, path_length);
    return -1;
  }
  snprintf(path, path_length, "%s/%s", path_prefix, path_suffix);
2364
  int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC));
2365
  if (fd == -1) {
2366
    free(path);
2367
    return -2; // Distinguish failure to find any data from failure to find a specific id.
2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379
  }

  // 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;
2380 2381 2382 2383 2384
  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");
2385
    free(path);
2386 2387 2388 2389 2390
    close(fd);
    return -1;
  }

  if (strncmp(header.tzdata_version, "tzdata", 6) != 0 || header.tzdata_version[11] != 0) {
2391 2392
    fprintf(stderr, "%s: bad magic in \"%s\": \"%.6s\"\n",
            __FUNCTION__, path, header.tzdata_version);
2393
    free(path);
2394 2395 2396 2397 2398
    close(fd);
    return -1;
  }

#if 0
2399
  fprintf(stderr, "version: %s\n", header.tzdata_version);
2400 2401 2402 2403 2404 2405
  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) {
2406 2407
    fprintf(stderr, "%s: couldn't seek to index in \"%s\": %s\n",
            __FUNCTION__, path, strerror(errno));
2408
    free(path);
2409 2410 2411 2412 2413
    close(fd);
    return -1;
  }

  off_t specific_zone_offset = -1;
2414 2415
  ssize_t index_size = ntohl(header.data_offset) - ntohl(header.index_offset);
  char* index = malloc(index_size);
2416 2417 2418 2419 2420 2421 2422
  if (index == NULL) {
    fprintf(stderr, "%s: couldn't allocate %zd-byte index for \"%s\"\n",
            __FUNCTION__, index_size, path);
    free(path);
    close(fd);
    return -1;
  }
2423 2424 2425
  if (TEMP_FAILURE_RETRY(read(fd, index, index_size)) != index_size) {
    fprintf(stderr, "%s: could not read index of \"%s\": %s\n",
            __FUNCTION__, path, (bytes_read == -1) ? strerror(errno) : "short read");
2426
    free(path);
2427 2428 2429 2430
    free(index);
    close(fd);
    return -1;
  }
2431

2432
  static const size_t NAME_LENGTH = 40;
2433 2434 2435 2436
  struct index_entry_t {
    char buf[NAME_LENGTH];
    int32_t start;
    int32_t length;
Elliott Hughes's avatar
Elliott Hughes committed
2437
    int32_t unused; // Was raw GMT offset; always 0 since tzdata2014f (L).
2438 2439 2440 2441
  };

  size_t id_count = (ntohl(header.data_offset) - ntohl(header.index_offset)) / sizeof(struct index_entry_t);
  struct index_entry_t* entry = (struct index_entry_t*) index;
2442
  for (size_t i = 0; i < id_count; ++i) {
2443
    char this_id[NAME_LENGTH + 1];
2444
    memcpy(this_id, entry->buf, NAME_LENGTH);
2445
    this_id[NAME_LENGTH] = '\0';
2446 2447

    if (strcmp(this_id, olson_id) == 0) {
2448
      specific_zone_offset = ntohl(entry->start) + ntohl(header.data_offset);
Elliott Hughes's avatar
Elliott Hughes committed
2449
      *entry_length = ntohl(entry->length);
2450 2451
      break;
    }
2452 2453

    ++entry;
2454
  }
2455
  free(index);
2456 2457

  if (specific_zone_offset == -1) {
2458
    free(path);
2459 2460 2461 2462 2463
    close(fd);
    return -1;
  }

  if (TEMP_FAILURE_RETRY(lseek(fd, specific_zone_offset, SEEK_SET)) == -1) {
2464 2465
    fprintf(stderr, "%s: could not seek to %ld in \"%s\": %s\n",
            __FUNCTION__, specific_zone_offset, path, strerror(errno));
2466
    free(path);
2467 2468 2469 2470
    close(fd);
    return -1;
  }

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

2473
  free(path);
2474 2475
  return fd;
}
2476

Elliott Hughes's avatar
Elliott Hughes committed
2477 2478 2479
static int __bionic_open_tzdata(const char* olson_id, int32_t* entry_length) {
  int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/current/tzdata",
                                     olson_id, entry_length);
2480
  if (fd < 0) {
Elliott Hughes's avatar
Elliott Hughes committed
2481 2482
    fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata",
                                   olson_id, entry_length);
2483 2484 2485 2486 2487
    if (fd == -2) {
      // 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);
    }
2488 2489 2490
  }
  return fd;
}
Elliott Hughes's avatar
Elliott Hughes committed
2491 2492

// END android-added