117209Swollman/*
217209Swollman** This file is in the public domain, so clarified as of
3192625Sedwin** 1996-06-05 by Arthur David Olson.
417209Swollman*/
515923Sscrappy
6111010Snectar#include <sys/cdefs.h>
72708Swollman#ifndef lint
82708Swollman#ifndef NOID
9214411Sedwinstatic char	elsieid[] __unused = "@(#)localtime.c	8.14";
102708Swollman#endif /* !defined NOID */
112708Swollman#endif /* !defined lint */
1292986Sobrien__FBSDID("$FreeBSD: stable/10/contrib/tzcode/stdtime/localtime.c 314446 2017-03-01 01:44:40Z emaste $");
132708Swollman
142708Swollman/*
15192625Sedwin** Leap second handling from Bradley White.
16192625Sedwin** POSIX-style TZ environment variable handling from Guy Harris.
172708Swollman*/
182708Swollman
192708Swollman/*LINTLIBRARY*/
202708Swollman
2171579Sdeischen#include "namespace.h"
2218834Swollman#include <sys/types.h>
2318834Swollman#include <sys/stat.h>
24197189Sedwin#include <errno.h>
2571579Sdeischen#include <fcntl.h>
2671579Sdeischen#include <pthread.h>
2771579Sdeischen#include "private.h"
2871579Sdeischen#include "un-namespace.h"
2918834Swollman
302708Swollman#include "tzfile.h"
31192625Sedwin#include "float.h"	/* for FLT_MAX and DBL_MAX */
322708Swollman
33192625Sedwin#ifndef TZ_ABBR_MAX_LEN
34192625Sedwin#define TZ_ABBR_MAX_LEN	16
35192625Sedwin#endif /* !defined TZ_ABBR_MAX_LEN */
36192625Sedwin
37192625Sedwin#ifndef TZ_ABBR_CHAR_SET
38192625Sedwin#define TZ_ABBR_CHAR_SET \
39192625Sedwin	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
40192625Sedwin#endif /* !defined TZ_ABBR_CHAR_SET */
41192625Sedwin
42192625Sedwin#ifndef TZ_ABBR_ERR_CHAR
43192625Sedwin#define TZ_ABBR_ERR_CHAR	'_'
44192625Sedwin#endif /* !defined TZ_ABBR_ERR_CHAR */
45192625Sedwin
4671579Sdeischen#include "libc_private.h"
4771579Sdeischen
4871579Sdeischen#define	_MUTEX_LOCK(x)		if (__isthreaded) _pthread_mutex_lock(x)
4971579Sdeischen#define	_MUTEX_UNLOCK(x)	if (__isthreaded) _pthread_mutex_unlock(x)
5071579Sdeischen
51177824Sdavidxu#define _RWLOCK_RDLOCK(x)						\
52177824Sdavidxu		do {							\
53177824Sdavidxu			if (__isthreaded) _pthread_rwlock_rdlock(x);	\
54177824Sdavidxu		} while (0)
55177824Sdavidxu
56177824Sdavidxu#define _RWLOCK_WRLOCK(x)						\
57177824Sdavidxu		do {							\
58177824Sdavidxu			if (__isthreaded) _pthread_rwlock_wrlock(x);	\
59177824Sdavidxu		} while (0)
60177824Sdavidxu
61177824Sdavidxu#define _RWLOCK_UNLOCK(x)						\
62177824Sdavidxu		do {							\
63177824Sdavidxu			if (__isthreaded) _pthread_rwlock_unlock(x);	\
64177824Sdavidxu		} while (0)
65177824Sdavidxu
669936Swollman/*
679936Swollman** SunOS 4.1.1 headers lack O_BINARY.
689936Swollman*/
692708Swollman
702708Swollman#ifdef O_BINARY
712708Swollman#define OPEN_MODE	(O_RDONLY | O_BINARY)
722708Swollman#endif /* defined O_BINARY */
732708Swollman#ifndef O_BINARY
742708Swollman#define OPEN_MODE	O_RDONLY
752708Swollman#endif /* !defined O_BINARY */
762708Swollman
772708Swollman#ifndef WILDABBR
782708Swollman/*
792708Swollman** Someone might make incorrect use of a time zone abbreviation:
802708Swollman**	1.	They might reference tzname[0] before calling tzset (explicitly
819936Swollman**		or implicitly).
822708Swollman**	2.	They might reference tzname[1] before calling tzset (explicitly
839936Swollman**		or implicitly).
842708Swollman**	3.	They might reference tzname[1] after setting to a time zone
852708Swollman**		in which Daylight Saving Time is never observed.
862708Swollman**	4.	They might reference tzname[0] after setting to a time zone
872708Swollman**		in which Standard Time is never observed.
882708Swollman**	5.	They might reference tm.TM_ZONE after calling offtime.
892708Swollman** What's best to do in the above cases is open to debate;
902708Swollman** for now, we just set things up so that in any of the five cases
91192625Sedwin** WILDABBR is used. Another possibility: initialize tzname[0] to the
922708Swollman** string "tzname[0] used before set", and similarly for the other cases.
93192625Sedwin** And another: initialize tzname[0] to "ERA", with an explanation in the
942708Swollman** manual page of what this "time zone abbreviation" means (doing this so
952708Swollman** that tzname[0] has the "normal" length of three characters).
962708Swollman*/
972708Swollman#define WILDABBR	"   "
982708Swollman#endif /* !defined WILDABBR */
992708Swollman
100192625Sedwinstatic char		wildabbr[] = WILDABBR;
1012708Swollman
102130332Skensmith/*
103130332Skensmith * In June 2004 it was decided UTC was a more appropriate default time
104130332Skensmith * zone than GMT.
105130332Skensmith */
1069936Swollman
107130332Skensmithstatic const char	gmt[] = "UTC";
108130332Skensmith
109130461Sstefanf/*
110130461Sstefanf** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
111130461Sstefanf** We default to US rules as of 1999-08-17.
112130461Sstefanf** POSIX 1003.1 section 8.1.1 says that the default DST rules are
113130461Sstefanf** implementation dependent; for historical reasons, US rules are a
114130461Sstefanf** common default.
115130461Sstefanf*/
116130461Sstefanf#ifndef TZDEFRULESTRING
117130461Sstefanf#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
118130461Sstefanf#endif /* !defined TZDEFDST */
119130461Sstefanf
1202708Swollmanstruct ttinfo {				/* time type information */
121130461Sstefanf	long		tt_gmtoff;	/* UTC offset in seconds */
1222708Swollman	int		tt_isdst;	/* used to set tm_isdst */
1232708Swollman	int		tt_abbrind;	/* abbreviation list index */
1242708Swollman	int		tt_ttisstd;	/* TRUE if transition is std time */
125130461Sstefanf	int		tt_ttisgmt;	/* TRUE if transition is UTC */
1262708Swollman};
1272708Swollman
1282708Swollmanstruct lsinfo {				/* leap second information */
1292708Swollman	time_t		ls_trans;	/* transition time */
1302708Swollman	long		ls_corr;	/* correction to apply */
1312708Swollman};
1322708Swollman
1332708Swollman#define BIGGEST(a, b)	(((a) > (b)) ? (a) : (b))
1342708Swollman
1352708Swollman#ifdef TZNAME_MAX
1362708Swollman#define MY_TZNAME_MAX	TZNAME_MAX
1372708Swollman#endif /* defined TZNAME_MAX */
1382708Swollman#ifndef TZNAME_MAX
1392708Swollman#define MY_TZNAME_MAX	255
1402708Swollman#endif /* !defined TZNAME_MAX */
1412708Swollman
1422708Swollmanstruct state {
1432708Swollman	int		leapcnt;
1442708Swollman	int		timecnt;
1452708Swollman	int		typecnt;
1462708Swollman	int		charcnt;
147192625Sedwin	int		goback;
148192625Sedwin	int		goahead;
1492708Swollman	time_t		ats[TZ_MAX_TIMES];
1502708Swollman	unsigned char	types[TZ_MAX_TIMES];
1512708Swollman	struct ttinfo	ttis[TZ_MAX_TYPES];
1529936Swollman	char		chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
1532708Swollman				(2 * (MY_TZNAME_MAX + 1)))];
1542708Swollman	struct lsinfo	lsis[TZ_MAX_LEAPS];
1552708Swollman};
1562708Swollman
1572708Swollmanstruct rule {
1582708Swollman	int		r_type;		/* type of rule--see below */
1592708Swollman	int		r_day;		/* day number of rule */
1602708Swollman	int		r_week;		/* week number of rule */
1612708Swollman	int		r_mon;		/* month number of rule */
1622708Swollman	long		r_time;		/* transition time of rule */
1632708Swollman};
1642708Swollman
1652708Swollman#define JULIAN_DAY		0	/* Jn - Julian day */
1662708Swollman#define DAY_OF_YEAR		1	/* n - day of year */
1672708Swollman#define MONTH_NTH_DAY_OF_WEEK	2	/* Mm.n.d - month, week, day of week */
1682708Swollman
1692708Swollman/*
1702708Swollman** Prototypes for static functions.
1712708Swollman*/
1722708Swollman
17397423Salfredstatic long		detzcode(const char * codep);
174192625Sedwinstatic time_t		detzcode64(const char * codep);
175192625Sedwinstatic int		differ_by_repeat(time_t t1, time_t t0);
17697423Salfredstatic const char *	getzname(const char * strp);
177192625Sedwinstatic const char *	getqzname(const char * strp, const int delim);
17897423Salfredstatic const char *	getnum(const char * strp, int * nump, int min,
17997423Salfred				int max);
18097423Salfredstatic const char *	getsecs(const char * strp, long * secsp);
18197423Salfredstatic const char *	getoffset(const char * strp, long * offsetp);
18297423Salfredstatic const char *	getrule(const char * strp, struct rule * rulep);
18397423Salfredstatic void		gmtload(struct state * sp);
184192625Sedwinstatic struct tm *	gmtsub(const time_t * timep, long offset,
18597423Salfred				struct tm * tmp);
186192625Sedwinstatic struct tm *	localsub(const time_t * timep, long offset,
18797423Salfred				struct tm * tmp);
18897423Salfredstatic int		increment_overflow(int * number, int delta);
189192625Sedwinstatic int		leaps_thru_end_of(int y);
190192625Sedwinstatic int		long_increment_overflow(long * number, int delta);
191192625Sedwinstatic int		long_normalize_overflow(long * tensptr,
192192625Sedwin				int * unitsptr, int base);
19397423Salfredstatic int		normalize_overflow(int * tensptr, int * unitsptr,
19497423Salfred				int base);
19597423Salfredstatic void		settzname(void);
19697423Salfredstatic time_t		time1(struct tm * tmp,
197192625Sedwin				struct tm * (*funcp)(const time_t *,
19897423Salfred				long, struct tm *),
19997423Salfred				long offset);
20097423Salfredstatic time_t		time2(struct tm *tmp,
201192625Sedwin				struct tm * (*funcp)(const time_t *,
20297423Salfred				long, struct tm*),
20397423Salfred				long offset, int * okayp);
204130461Sstefanfstatic time_t		time2sub(struct tm *tmp,
205192625Sedwin				struct tm * (*funcp)(const time_t *,
206130461Sstefanf				long, struct tm*),
207130461Sstefanf				long offset, int * okayp, int do_norm_secs);
208192625Sedwinstatic struct tm *	timesub(const time_t * timep, long offset,
20997423Salfred				const struct state * sp, struct tm * tmp);
21097423Salfredstatic int		tmcomp(const struct tm * atmp,
21197423Salfred				const struct tm * btmp);
21297423Salfredstatic time_t		transtime(time_t janfirst, int year,
21397423Salfred				const struct rule * rulep, long offset);
214192625Sedwinstatic int		typesequiv(const struct state * sp, int a, int b);
215192625Sedwinstatic int		tzload(const char * name, struct state * sp,
216192625Sedwin				int doextend);
21797423Salfredstatic int		tzparse(const char * name, struct state * sp,
21897423Salfred				int lastditch);
2192708Swollman
2202708Swollman#ifdef ALL_STATE
2212708Swollmanstatic struct state *	lclptr;
2222708Swollmanstatic struct state *	gmtptr;
2232708Swollman#endif /* defined ALL_STATE */
2242708Swollman
2252708Swollman#ifndef ALL_STATE
2262708Swollmanstatic struct state	lclmem;
2272708Swollmanstatic struct state	gmtmem;
2282708Swollman#define lclptr		(&lclmem)
2292708Swollman#define gmtptr		(&gmtmem)
2302708Swollman#endif /* State Farm */
2312708Swollman
2329936Swollman#ifndef TZ_STRLEN_MAX
2339936Swollman#define TZ_STRLEN_MAX 255
2349936Swollman#endif /* !defined TZ_STRLEN_MAX */
2359936Swollman
2369936Swollmanstatic char		lcl_TZname[TZ_STRLEN_MAX + 1];
2372708Swollmanstatic int		lcl_is_set;
238199607Sjhbstatic pthread_once_t	gmt_once = PTHREAD_ONCE_INIT;
239177824Sdavidxustatic pthread_rwlock_t	lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER;
240201270Sjhbstatic pthread_once_t	gmtime_once = PTHREAD_ONCE_INIT;
241201270Sjhbstatic pthread_key_t	gmtime_key;
242201270Sjhbstatic int		gmtime_key_error;
243200797Sjhbstatic pthread_once_t	localtime_once = PTHREAD_ONCE_INIT;
244200797Sjhbstatic pthread_key_t	localtime_key;
245200797Sjhbstatic int		localtime_key_error;
2462708Swollman
2472708Swollmanchar *			tzname[2] = {
2489936Swollman	wildabbr,
2499936Swollman	wildabbr
2502708Swollman};
2512708Swollman
2529936Swollman/*
2539936Swollman** Section 4.12.3 of X3.159-1989 requires that
2549936Swollman**	Except for the strftime function, these functions [asctime,
2559936Swollman**	ctime, gmtime, localtime] return values in one of two static
2569936Swollman**	objects: a broken-down time structure and an array of char.
257192625Sedwin** Thanks to Paul Eggert for noting this.
2589936Swollman*/
2599936Swollman
2609936Swollmanstatic struct tm	tm;
2619936Swollman
2622708Swollman#ifdef USG_COMPAT
2632708Swollmantime_t			timezone = 0;
2642708Swollmanint			daylight = 0;
2652708Swollman#endif /* defined USG_COMPAT */
2662708Swollman
2672708Swollman#ifdef ALTZONE
2682708Swollmantime_t			altzone = 0;
2692708Swollman#endif /* defined ALTZONE */
2702708Swollman
2712708Swollmanstatic long
2722708Swollmandetzcode(codep)
2732708Swollmanconst char * const	codep;
2742708Swollman{
27592889Sobrien	long	result;
27692889Sobrien	int	i;
2772708Swollman
278192625Sedwin	result = (codep[0] & 0x80) ? ~0L : 0;
2792708Swollman	for (i = 0; i < 4; ++i)
2802708Swollman		result = (result << 8) | (codep[i] & 0xff);
2812708Swollman	return result;
2822708Swollman}
2832708Swollman
284192625Sedwinstatic time_t
285192625Sedwindetzcode64(codep)
286192625Sedwinconst char * const	codep;
287192625Sedwin{
288192625Sedwin	register time_t	result;
289192625Sedwin	register int	i;
290192625Sedwin
291192625Sedwin	result = (codep[0] & 0x80) ?  (~(int_fast64_t) 0) : 0;
292192625Sedwin	for (i = 0; i < 8; ++i)
293192625Sedwin		result = result * 256 + (codep[i] & 0xff);
294192625Sedwin	return result;
295192625Sedwin}
296192625Sedwin
2972708Swollmanstatic void
29897423Salfredsettzname(void)
2992708Swollman{
30092889Sobrien	struct state * 	sp = lclptr;
30192889Sobrien	int			i;
3022708Swollman
3039936Swollman	tzname[0] = wildabbr;
3049936Swollman	tzname[1] = wildabbr;
3052708Swollman#ifdef USG_COMPAT
3062708Swollman	daylight = 0;
3072708Swollman	timezone = 0;
3082708Swollman#endif /* defined USG_COMPAT */
3092708Swollman#ifdef ALTZONE
3102708Swollman	altzone = 0;
3112708Swollman#endif /* defined ALTZONE */
3122708Swollman#ifdef ALL_STATE
3132708Swollman	if (sp == NULL) {
3149936Swollman		tzname[0] = tzname[1] = gmt;
3152708Swollman		return;
3162708Swollman	}
3172708Swollman#endif /* defined ALL_STATE */
318214411Sedwin	/*
319214411Sedwin	** And to get the latest zone names into tzname. . .
320214411Sedwin	*/
3212708Swollman	for (i = 0; i < sp->typecnt; ++i) {
322214411Sedwin		const struct ttinfo * const ttisp = &sp->ttis[sp->types[i]];
3232708Swollman
3242708Swollman		tzname[ttisp->tt_isdst] =
3259936Swollman			&sp->chars[ttisp->tt_abbrind];
3262708Swollman#ifdef USG_COMPAT
3272708Swollman		if (ttisp->tt_isdst)
3282708Swollman			daylight = 1;
329214411Sedwin		if (!ttisp->tt_isdst)
3302708Swollman			timezone = -(ttisp->tt_gmtoff);
3312708Swollman#endif /* defined USG_COMPAT */
3322708Swollman#ifdef ALTZONE
333214411Sedwin		if (ttisp->tt_isdst)
3342708Swollman			altzone = -(ttisp->tt_gmtoff);
3352708Swollman#endif /* defined ALTZONE */
3362708Swollman	}
3372708Swollman	/*
338192625Sedwin	** Finally, scrub the abbreviations.
339192625Sedwin	** First, replace bogus characters.
340192625Sedwin	*/
341192625Sedwin	for (i = 0; i < sp->charcnt; ++i)
342192625Sedwin		if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
343192625Sedwin			sp->chars[i] = TZ_ABBR_ERR_CHAR;
344192625Sedwin	/*
345192625Sedwin	** Second, truncate long abbreviations.
346192625Sedwin	*/
347192625Sedwin	for (i = 0; i < sp->typecnt; ++i) {
348192625Sedwin		register const struct ttinfo * const	ttisp = &sp->ttis[i];
349192625Sedwin		register char *				cp = &sp->chars[ttisp->tt_abbrind];
350192625Sedwin
351192625Sedwin		if (strlen(cp) > TZ_ABBR_MAX_LEN &&
352192625Sedwin			strcmp(cp, GRANDPARENTED) != 0)
353192625Sedwin				*(cp + TZ_ABBR_MAX_LEN) = '\0';
354192625Sedwin	}
3552708Swollman}
3562708Swollman
3572708Swollmanstatic int
358192625Sedwindiffer_by_repeat(t1, t0)
359192625Sedwinconst time_t	t1;
360192625Sedwinconst time_t	t0;
361192625Sedwin{
362192625Sedwin	int_fast64_t _t0 = t0;
363192625Sedwin	int_fast64_t _t1 = t1;
364192625Sedwin
365192625Sedwin	if (TYPE_INTEGRAL(time_t) &&
366192625Sedwin		TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
367192625Sedwin			return 0;
368192625Sedwin	//turn ((int_fast64_t)(t1 - t0) == SECSPERREPEAT);
369192625Sedwin	return _t1 - _t0 == SECSPERREPEAT;
370192625Sedwin}
371192625Sedwin
372192625Sedwinstatic int
373192625Sedwintzload(name, sp, doextend)
37492889Sobrienconst char *		name;
37592889Sobrienstruct state * const	sp;
376192625Sedwinregister const int	doextend;
3772708Swollman{
37892889Sobrien	const char *	p;
37992889Sobrien	int		i;
38092889Sobrien	int		fid;
381192625Sedwin	int		stored;
382192625Sedwin	int		nread;
383225677Skib	int		res;
384192625Sedwin	union {
385192625Sedwin		struct tzhead	tzhead;
386192625Sedwin		char		buf[2 * sizeof(struct tzhead) +
387192625Sedwin					2 * sizeof *sp +
388192625Sedwin					4 * TZ_MAX_TIMES];
389225677Skib	} *u;
3902708Swollman
391225677Skib	u = NULL;
392225677Skib	res = -1;
393214411Sedwin	sp->goback = sp->goahead = FALSE;
394214411Sedwin
39539327Simp	/* XXX The following is from OpenBSD, and I'm not sure it is correct */
39639327Simp	if (name != NULL && issetugid() != 0)
39739327Simp		if ((name[0] == ':' && name[1] == '/') ||
39839327Simp		    name[0] == '/' || strchr(name, '.'))
39939327Simp			name = NULL;
4002708Swollman	if (name == NULL && (name = TZDEFAULT) == NULL)
4012708Swollman		return -1;
4022708Swollman	{
40392889Sobrien		int	doaccess;
40418834Swollman		struct stat	stab;
4059936Swollman		/*
4069936Swollman		** Section 4.9.1 of the C standard says that
4079936Swollman		** "FILENAME_MAX expands to an integral constant expression
40818834Swollman		** that is the size needed for an array of char large enough
4099936Swollman		** to hold the longest file name string that the implementation
4109936Swollman		** guarantees can be opened."
4119936Swollman		*/
412225677Skib		char		*fullname;
4132708Swollman
414225677Skib		fullname = malloc(FILENAME_MAX + 1);
415225677Skib		if (fullname == NULL)
416225677Skib			goto out;
417225677Skib
4182708Swollman		if (name[0] == ':')
4192708Swollman			++name;
4202708Swollman		doaccess = name[0] == '/';
4212708Swollman		if (!doaccess) {
422225677Skib			if ((p = TZDIR) == NULL) {
423225677Skib				free(fullname);
4242708Swollman				return -1;
425225677Skib			}
426225677Skib			if (strlen(p) + 1 + strlen(name) >= FILENAME_MAX) {
427225677Skib				free(fullname);
4282708Swollman				return -1;
429225677Skib			}
4302708Swollman			(void) strcpy(fullname, p);
4312708Swollman			(void) strcat(fullname, "/");
4322708Swollman			(void) strcat(fullname, name);
4332708Swollman			/*
4342708Swollman			** Set doaccess if '.' (as in "../") shows up in name.
4352708Swollman			*/
4362708Swollman			if (strchr(name, '.') != NULL)
4372708Swollman				doaccess = TRUE;
4382708Swollman			name = fullname;
4392708Swollman		}
440225677Skib		if (doaccess && access(name, R_OK) != 0) {
441225677Skib			free(fullname);
44239327Simp		     	return -1;
443225677Skib		}
444225677Skib		if ((fid = _open(name, OPEN_MODE)) == -1) {
445225677Skib			free(fullname);
4462708Swollman			return -1;
447225677Skib		}
44895989Swollman		if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) {
449225677Skib			free(fullname);
45095989Swollman			_close(fid);
45118834Swollman			return -1;
45295989Swollman		}
453226828Strociny		free(fullname);
4542708Swollman	}
455225677Skib	u = malloc(sizeof(*u));
456225677Skib	if (u == NULL)
457225677Skib		goto out;
458225677Skib	nread = _read(fid, u->buf, sizeof u->buf);
459192625Sedwin	if (_close(fid) < 0 || nread <= 0)
460225677Skib		goto out;
461192625Sedwin	for (stored = 4; stored <= 8; stored *= 2) {
4629936Swollman		int		ttisstdcnt;
4639936Swollman		int		ttisgmtcnt;
4642708Swollman
465225677Skib		ttisstdcnt = (int) detzcode(u->tzhead.tzh_ttisstdcnt);
466225677Skib		ttisgmtcnt = (int) detzcode(u->tzhead.tzh_ttisgmtcnt);
467225677Skib		sp->leapcnt = (int) detzcode(u->tzhead.tzh_leapcnt);
468225677Skib		sp->timecnt = (int) detzcode(u->tzhead.tzh_timecnt);
469225677Skib		sp->typecnt = (int) detzcode(u->tzhead.tzh_typecnt);
470225677Skib		sp->charcnt = (int) detzcode(u->tzhead.tzh_charcnt);
471225677Skib		p = u->tzhead.tzh_charcnt + sizeof u->tzhead.tzh_charcnt;
4722708Swollman		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
4732708Swollman			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
4742708Swollman			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
4752708Swollman			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
4769936Swollman			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
4779936Swollman			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
478225677Skib				goto out;
479225677Skib		if (nread - (p - u->buf) <
480192625Sedwin			sp->timecnt * stored +		/* ats */
4819936Swollman			sp->timecnt +			/* types */
482192625Sedwin			sp->typecnt * 6 +		/* ttinfos */
4839936Swollman			sp->charcnt +			/* chars */
484192625Sedwin			sp->leapcnt * (stored + 4) +	/* lsinfos */
4859936Swollman			ttisstdcnt +			/* ttisstds */
4869936Swollman			ttisgmtcnt)			/* ttisgmts */
487225677Skib				goto out;
4882708Swollman		for (i = 0; i < sp->timecnt; ++i) {
489192625Sedwin			sp->ats[i] = (stored == 4) ?
490192625Sedwin				detzcode(p) : detzcode64(p);
491192625Sedwin			p += stored;
4922708Swollman		}
4932708Swollman		for (i = 0; i < sp->timecnt; ++i) {
4942708Swollman			sp->types[i] = (unsigned char) *p++;
4952708Swollman			if (sp->types[i] >= sp->typecnt)
496225677Skib				goto out;
4972708Swollman		}
4982708Swollman		for (i = 0; i < sp->typecnt; ++i) {
49992889Sobrien			struct ttinfo *	ttisp;
5002708Swollman
5012708Swollman			ttisp = &sp->ttis[i];
5022708Swollman			ttisp->tt_gmtoff = detzcode(p);
5032708Swollman			p += 4;
5042708Swollman			ttisp->tt_isdst = (unsigned char) *p++;
5052708Swollman			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
506225677Skib				goto out;
5072708Swollman			ttisp->tt_abbrind = (unsigned char) *p++;
5082708Swollman			if (ttisp->tt_abbrind < 0 ||
5092708Swollman				ttisp->tt_abbrind > sp->charcnt)
510225677Skib					goto out;
5112708Swollman		}
5122708Swollman		for (i = 0; i < sp->charcnt; ++i)
5132708Swollman			sp->chars[i] = *p++;
5142708Swollman		sp->chars[i] = '\0';	/* ensure '\0' at end */
5152708Swollman		for (i = 0; i < sp->leapcnt; ++i) {
51692889Sobrien			struct lsinfo *	lsisp;
5172708Swollman
5182708Swollman			lsisp = &sp->lsis[i];
519192625Sedwin			lsisp->ls_trans = (stored == 4) ?
520192625Sedwin				detzcode(p) : detzcode64(p);
521192625Sedwin			p += stored;
5222708Swollman			lsisp->ls_corr = detzcode(p);
5232708Swollman			p += 4;
5242708Swollman		}
5252708Swollman		for (i = 0; i < sp->typecnt; ++i) {
52692889Sobrien			struct ttinfo *	ttisp;
5272708Swollman
5282708Swollman			ttisp = &sp->ttis[i];
5292708Swollman			if (ttisstdcnt == 0)
5302708Swollman				ttisp->tt_ttisstd = FALSE;
5312708Swollman			else {
5322708Swollman				ttisp->tt_ttisstd = *p++;
5332708Swollman				if (ttisp->tt_ttisstd != TRUE &&
5342708Swollman					ttisp->tt_ttisstd != FALSE)
535225677Skib						goto out;
5362708Swollman			}
5372708Swollman		}
5389936Swollman		for (i = 0; i < sp->typecnt; ++i) {
53992889Sobrien			struct ttinfo *	ttisp;
5409936Swollman
5419936Swollman			ttisp = &sp->ttis[i];
5429936Swollman			if (ttisgmtcnt == 0)
5439936Swollman				ttisp->tt_ttisgmt = FALSE;
5449936Swollman			else {
5459936Swollman				ttisp->tt_ttisgmt = *p++;
5469936Swollman				if (ttisp->tt_ttisgmt != TRUE &&
5479936Swollman					ttisp->tt_ttisgmt != FALSE)
548225677Skib						goto out;
5499936Swollman			}
5509936Swollman		}
551192625Sedwin		/*
552192625Sedwin		** Out-of-sort ats should mean we're running on a
553192625Sedwin		** signed time_t system but using a data file with
554192625Sedwin		** unsigned values (or vice versa).
555192625Sedwin		*/
556192625Sedwin		for (i = 0; i < sp->timecnt - 2; ++i)
557192625Sedwin			if (sp->ats[i] > sp->ats[i + 1]) {
558192625Sedwin				++i;
559192625Sedwin				if (TYPE_SIGNED(time_t)) {
560192625Sedwin					/*
561192625Sedwin					** Ignore the end (easy).
562192625Sedwin					*/
563192625Sedwin					sp->timecnt = i;
564192625Sedwin				} else {
565192625Sedwin					/*
566192625Sedwin					** Ignore the beginning (harder).
567192625Sedwin					*/
568192625Sedwin					register int	j;
569192625Sedwin
570192625Sedwin					for (j = 0; j + i < sp->timecnt; ++j) {
571192625Sedwin						sp->ats[j] = sp->ats[j + i];
572192625Sedwin						sp->types[j] = sp->types[j + i];
573192625Sedwin					}
574192625Sedwin					sp->timecnt = j;
575192625Sedwin				}
576192625Sedwin				break;
577192625Sedwin			}
578192625Sedwin		/*
579192625Sedwin		** If this is an old file, we're done.
580192625Sedwin		*/
581225677Skib		if (u->tzhead.tzh_version[0] == '\0')
582192625Sedwin			break;
583225677Skib		nread -= p - u->buf;
584192625Sedwin		for (i = 0; i < nread; ++i)
585225677Skib			u->buf[i] = p[i];
586192625Sedwin		/*
587192625Sedwin		** If this is a narrow integer time_t system, we're done.
588192625Sedwin		*/
589192625Sedwin		if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
590192625Sedwin			break;
5912708Swollman	}
592192625Sedwin	if (doextend && nread > 2 &&
593225677Skib		u->buf[0] == '\n' && u->buf[nread - 1] == '\n' &&
594192625Sedwin		sp->typecnt + 2 <= TZ_MAX_TYPES) {
595225677Skib			struct state	*ts;
596192625Sedwin			register int	result;
597192625Sedwin
598225677Skib			ts = malloc(sizeof(*ts));
599225677Skib			if (ts == NULL)
600225677Skib				goto out;
601225677Skib			u->buf[nread - 1] = '\0';
602225677Skib			result = tzparse(&u->buf[1], ts, FALSE);
603225677Skib			if (result == 0 && ts->typecnt == 2 &&
604225677Skib				sp->charcnt + ts->charcnt <= TZ_MAX_CHARS) {
605192625Sedwin					for (i = 0; i < 2; ++i)
606225677Skib						ts->ttis[i].tt_abbrind +=
607192625Sedwin							sp->charcnt;
608225677Skib					for (i = 0; i < ts->charcnt; ++i)
609192625Sedwin						sp->chars[sp->charcnt++] =
610225677Skib							ts->chars[i];
611192625Sedwin					i = 0;
612225677Skib					while (i < ts->timecnt &&
613225677Skib						ts->ats[i] <=
614192625Sedwin						sp->ats[sp->timecnt - 1])
615192625Sedwin							++i;
616225677Skib					while (i < ts->timecnt &&
617192625Sedwin					    sp->timecnt < TZ_MAX_TIMES) {
618192625Sedwin						sp->ats[sp->timecnt] =
619225677Skib							ts->ats[i];
620192625Sedwin						sp->types[sp->timecnt] =
621192625Sedwin							sp->typecnt +
622225677Skib							ts->types[i];
623192625Sedwin						++sp->timecnt;
624192625Sedwin						++i;
625192625Sedwin					}
626225677Skib					sp->ttis[sp->typecnt++] = ts->ttis[0];
627225677Skib					sp->ttis[sp->typecnt++] = ts->ttis[1];
628192625Sedwin			}
629225677Skib			free(ts);
630192625Sedwin	}
631192625Sedwin	if (sp->timecnt > 1) {
632192625Sedwin		for (i = 1; i < sp->timecnt; ++i)
633192625Sedwin			if (typesequiv(sp, sp->types[i], sp->types[0]) &&
634192625Sedwin				differ_by_repeat(sp->ats[i], sp->ats[0])) {
635192625Sedwin					sp->goback = TRUE;
636192625Sedwin					break;
637192625Sedwin				}
638192625Sedwin		for (i = sp->timecnt - 2; i >= 0; --i)
639192625Sedwin			if (typesequiv(sp, sp->types[sp->timecnt - 1],
640192625Sedwin				sp->types[i]) &&
641192625Sedwin				differ_by_repeat(sp->ats[sp->timecnt - 1],
642192625Sedwin				sp->ats[i])) {
643192625Sedwin					sp->goahead = TRUE;
644192625Sedwin					break;
645192625Sedwin		}
646192625Sedwin	}
647225677Skib	res = 0;
648225677Skibout:
649225677Skib	free(u);
650225677Skib	return (res);
6512708Swollman}
6522708Swollman
653192625Sedwinstatic int
654192625Sedwintypesequiv(sp, a, b)
655192625Sedwinconst struct state * const	sp;
656192625Sedwinconst int			a;
657192625Sedwinconst int			b;
658192625Sedwin{
659192625Sedwin	register int	result;
660192625Sedwin
661192625Sedwin	if (sp == NULL ||
662192625Sedwin		a < 0 || a >= sp->typecnt ||
663192625Sedwin		b < 0 || b >= sp->typecnt)
664192625Sedwin			result = FALSE;
665192625Sedwin	else {
666192625Sedwin		register const struct ttinfo *	ap = &sp->ttis[a];
667192625Sedwin		register const struct ttinfo *	bp = &sp->ttis[b];
668192625Sedwin		result = ap->tt_gmtoff == bp->tt_gmtoff &&
669192625Sedwin			ap->tt_isdst == bp->tt_isdst &&
670192625Sedwin			ap->tt_ttisstd == bp->tt_ttisstd &&
671192625Sedwin			ap->tt_ttisgmt == bp->tt_ttisgmt &&
672192625Sedwin			strcmp(&sp->chars[ap->tt_abbrind],
673192625Sedwin			&sp->chars[bp->tt_abbrind]) == 0;
674192625Sedwin	}
675192625Sedwin	return result;
676192625Sedwin}
677192625Sedwin
6782708Swollmanstatic const int	mon_lengths[2][MONSPERYEAR] = {
6792708Swollman	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
6802708Swollman	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
6812708Swollman};
6822708Swollman
6832708Swollmanstatic const int	year_lengths[2] = {
6842708Swollman	DAYSPERNYEAR, DAYSPERLYEAR
6852708Swollman};
6862708Swollman
6872708Swollman/*
6882708Swollman** Given a pointer into a time zone string, scan until a character that is not
689192625Sedwin** a valid character in a zone name is found. Return a pointer to that
6902708Swollman** character.
6912708Swollman*/
6922708Swollman
6932708Swollmanstatic const char *
6942708Swollmangetzname(strp)
69592889Sobrienconst char *	strp;
6962708Swollman{
69792889Sobrien	char	c;
6982708Swollman
69917209Swollman	while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
7002708Swollman		c != '+')
7012708Swollman			++strp;
7022708Swollman	return strp;
7032708Swollman}
7042708Swollman
7052708Swollman/*
706192625Sedwin** Given a pointer into an extended time zone string, scan until the ending
707192625Sedwin** delimiter of the zone name is located. Return a pointer to the delimiter.
708192625Sedwin**
709192625Sedwin** As with getzname above, the legal character set is actually quite
710192625Sedwin** restricted, with other characters producing undefined results.
711192625Sedwin** We don't do any checking here; checking is done later in common-case code.
712192625Sedwin*/
713192625Sedwin
714192625Sedwinstatic const char *
715192625Sedwingetqzname(register const char *strp, const int delim)
716192625Sedwin{
717192625Sedwin	register int	c;
718192625Sedwin
719192625Sedwin	while ((c = *strp) != '\0' && c != delim)
720192625Sedwin		++strp;
721192625Sedwin	return strp;
722192625Sedwin}
723192625Sedwin
724192625Sedwin/*
7252708Swollman** Given a pointer into a time zone string, extract a number from that string.
7262708Swollman** Check that the number is within a specified range; if it is not, return
7272708Swollman** NULL.
7282708Swollman** Otherwise, return a pointer to the first character not part of the number.
7292708Swollman*/
7302708Swollman
7312708Swollmanstatic const char *
7322708Swollmangetnum(strp, nump, min, max)
73392889Sobrienconst char *	strp;
7342708Swollmanint * const		nump;
7352708Swollmanconst int		min;
7362708Swollmanconst int		max;
7372708Swollman{
73892889Sobrien	char	c;
73992889Sobrien	int	num;
7402708Swollman
74117209Swollman	if (strp == NULL || !is_digit(c = *strp))
7422708Swollman		return NULL;
7432708Swollman	num = 0;
74417209Swollman	do {
7452708Swollman		num = num * 10 + (c - '0');
7462708Swollman		if (num > max)
7472708Swollman			return NULL;	/* illegal value */
74817209Swollman		c = *++strp;
74917209Swollman	} while (is_digit(c));
7502708Swollman	if (num < min)
7512708Swollman		return NULL;		/* illegal value */
7522708Swollman	*nump = num;
7532708Swollman	return strp;
7542708Swollman}
7552708Swollman
7562708Swollman/*
7572708Swollman** Given a pointer into a time zone string, extract a number of seconds,
7582708Swollman** in hh[:mm[:ss]] form, from the string.
7592708Swollman** If any error occurs, return NULL.
7602708Swollman** Otherwise, return a pointer to the first character not part of the number
7612708Swollman** of seconds.
7622708Swollman*/
7632708Swollman
7642708Swollmanstatic const char *
7652708Swollmangetsecs(strp, secsp)
76692889Sobrienconst char *	strp;
7672708Swollmanlong * const		secsp;
7682708Swollman{
7692708Swollman	int	num;
7702708Swollman
7719936Swollman	/*
7729936Swollman	** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
7739936Swollman	** "M10.4.6/26", which does not conform to Posix,
7749936Swollman	** but which specifies the equivalent of
7759936Swollman	** ``02:00 on the first Sunday on or after 23 Oct''.
7769936Swollman	*/
7779936Swollman	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
7782708Swollman	if (strp == NULL)
7792708Swollman		return NULL;
7809936Swollman	*secsp = num * (long) SECSPERHOUR;
7812708Swollman	if (*strp == ':') {
7822708Swollman		++strp;
7832708Swollman		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
7842708Swollman		if (strp == NULL)
7852708Swollman			return NULL;
7862708Swollman		*secsp += num * SECSPERMIN;
7872708Swollman		if (*strp == ':') {
7882708Swollman			++strp;
789192625Sedwin			/* `SECSPERMIN' allows for leap seconds. */
7909936Swollman			strp = getnum(strp, &num, 0, SECSPERMIN);
7912708Swollman			if (strp == NULL)
7922708Swollman				return NULL;
7932708Swollman			*secsp += num;
7942708Swollman		}
7952708Swollman	}
7962708Swollman	return strp;
7972708Swollman}
7982708Swollman
7992708Swollman/*
8002708Swollman** Given a pointer into a time zone string, extract an offset, in
8012708Swollman** [+-]hh[:mm[:ss]] form, from the string.
8022708Swollman** If any error occurs, return NULL.
8032708Swollman** Otherwise, return a pointer to the first character not part of the time.
8042708Swollman*/
8052708Swollman
8062708Swollmanstatic const char *
8072708Swollmangetoffset(strp, offsetp)
80892889Sobrienconst char *	strp;
8092708Swollmanlong * const		offsetp;
8102708Swollman{
81192889Sobrien	int	neg = 0;
8122708Swollman
8132708Swollman	if (*strp == '-') {
8142708Swollman		neg = 1;
8152708Swollman		++strp;
81617209Swollman	} else if (*strp == '+')
81717209Swollman		++strp;
8182708Swollman	strp = getsecs(strp, offsetp);
8192708Swollman	if (strp == NULL)
8202708Swollman		return NULL;		/* illegal time */
8212708Swollman	if (neg)
8222708Swollman		*offsetp = -*offsetp;
8232708Swollman	return strp;
8242708Swollman}
8252708Swollman
8262708Swollman/*
8272708Swollman** Given a pointer into a time zone string, extract a rule in the form
828192625Sedwin** date[/time]. See POSIX section 8 for the format of "date" and "time".
8292708Swollman** If a valid rule is not found, return NULL.
8302708Swollman** Otherwise, return a pointer to the first character not part of the rule.
8312708Swollman*/
8322708Swollman
8332708Swollmanstatic const char *
8342708Swollmangetrule(strp, rulep)
8352708Swollmanconst char *			strp;
83692889Sobrienstruct rule * const	rulep;
8372708Swollman{
8382708Swollman	if (*strp == 'J') {
8392708Swollman		/*
8402708Swollman		** Julian day.
8412708Swollman		*/
8422708Swollman		rulep->r_type = JULIAN_DAY;
8432708Swollman		++strp;
8442708Swollman		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
8452708Swollman	} else if (*strp == 'M') {
8462708Swollman		/*
8472708Swollman		** Month, week, day.
8482708Swollman		*/
8492708Swollman		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
8502708Swollman		++strp;
8512708Swollman		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
8522708Swollman		if (strp == NULL)
8532708Swollman			return NULL;
8542708Swollman		if (*strp++ != '.')
8552708Swollman			return NULL;
8562708Swollman		strp = getnum(strp, &rulep->r_week, 1, 5);
8572708Swollman		if (strp == NULL)
8582708Swollman			return NULL;
8592708Swollman		if (*strp++ != '.')
8602708Swollman			return NULL;
8612708Swollman		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
86217209Swollman	} else if (is_digit(*strp)) {
8632708Swollman		/*
8642708Swollman		** Day of year.
8652708Swollman		*/
8662708Swollman		rulep->r_type = DAY_OF_YEAR;
8672708Swollman		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
8682708Swollman	} else	return NULL;		/* invalid format */
8692708Swollman	if (strp == NULL)
8702708Swollman		return NULL;
8712708Swollman	if (*strp == '/') {
8722708Swollman		/*
8732708Swollman		** Time specified.
8742708Swollman		*/
8752708Swollman		++strp;
8762708Swollman		strp = getsecs(strp, &rulep->r_time);
8772708Swollman	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
8782708Swollman	return strp;
8792708Swollman}
8802708Swollman
8812708Swollman/*
882130461Sstefanf** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
883130461Sstefanf** year, a rule, and the offset from UTC at the time that rule takes effect,
8842708Swollman** calculate the Epoch-relative time that rule takes effect.
8852708Swollman*/
8862708Swollman
8872708Swollmanstatic time_t
8882708Swollmantranstime(janfirst, year, rulep, offset)
8892708Swollmanconst time_t				janfirst;
8902708Swollmanconst int				year;
89192889Sobrienconst struct rule * const	rulep;
8922708Swollmanconst long				offset;
8932708Swollman{
89492889Sobrien	int	leapyear;
89592889Sobrien	time_t	value;
89692889Sobrien	int	i;
8972708Swollman	int		d, m1, yy0, yy1, yy2, dow;
8982708Swollman
8999936Swollman	INITIALIZE(value);
9002708Swollman	leapyear = isleap(year);
9012708Swollman	switch (rulep->r_type) {
9022708Swollman
9032708Swollman	case JULIAN_DAY:
9042708Swollman		/*
9052708Swollman		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
9062708Swollman		** years.
9072708Swollman		** In non-leap years, or if the day number is 59 or less, just
9082708Swollman		** add SECSPERDAY times the day number-1 to the time of
9092708Swollman		** January 1, midnight, to get the day.
9102708Swollman		*/
9112708Swollman		value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
9122708Swollman		if (leapyear && rulep->r_day >= 60)
9132708Swollman			value += SECSPERDAY;
9142708Swollman		break;
9152708Swollman
9162708Swollman	case DAY_OF_YEAR:
9172708Swollman		/*
9182708Swollman		** n - day of year.
9192708Swollman		** Just add SECSPERDAY times the day number to the time of
9202708Swollman		** January 1, midnight, to get the day.
9212708Swollman		*/
9222708Swollman		value = janfirst + rulep->r_day * SECSPERDAY;
9232708Swollman		break;
9242708Swollman
9252708Swollman	case MONTH_NTH_DAY_OF_WEEK:
9262708Swollman		/*
9272708Swollman		** Mm.n.d - nth "dth day" of month m.
9282708Swollman		*/
9292708Swollman		value = janfirst;
9302708Swollman		for (i = 0; i < rulep->r_mon - 1; ++i)
9312708Swollman			value += mon_lengths[leapyear][i] * SECSPERDAY;
9322708Swollman
9332708Swollman		/*
9342708Swollman		** Use Zeller's Congruence to get day-of-week of first day of
9352708Swollman		** month.
9362708Swollman		*/
9372708Swollman		m1 = (rulep->r_mon + 9) % 12 + 1;
9382708Swollman		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
9392708Swollman		yy1 = yy0 / 100;
9402708Swollman		yy2 = yy0 % 100;
9412708Swollman		dow = ((26 * m1 - 2) / 10 +
9422708Swollman			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
9432708Swollman		if (dow < 0)
9442708Swollman			dow += DAYSPERWEEK;
9452708Swollman
9462708Swollman		/*
947192625Sedwin		** "dow" is the day-of-week of the first day of the month. Get
9482708Swollman		** the day-of-month (zero-origin) of the first "dow" day of the
9492708Swollman		** month.
9502708Swollman		*/
9512708Swollman		d = rulep->r_day - dow;
9522708Swollman		if (d < 0)
9532708Swollman			d += DAYSPERWEEK;
9542708Swollman		for (i = 1; i < rulep->r_week; ++i) {
9552708Swollman			if (d + DAYSPERWEEK >=
9562708Swollman				mon_lengths[leapyear][rulep->r_mon - 1])
9572708Swollman					break;
9582708Swollman			d += DAYSPERWEEK;
9592708Swollman		}
9602708Swollman
9612708Swollman		/*
9622708Swollman		** "d" is the day-of-month (zero-origin) of the day we want.
9632708Swollman		*/
9642708Swollman		value += d * SECSPERDAY;
9652708Swollman		break;
9662708Swollman	}
9672708Swollman
9682708Swollman	/*
969130461Sstefanf	** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
970192625Sedwin	** question. To get the Epoch-relative time of the specified local
9712708Swollman	** time on that day, add the transition time and the current offset
972130461Sstefanf	** from UTC.
9732708Swollman	*/
9742708Swollman	return value + rulep->r_time + offset;
9752708Swollman}
9762708Swollman
9772708Swollman/*
9782708Swollman** Given a POSIX section 8-style TZ string, fill in the rule tables as
9792708Swollman** appropriate.
9802708Swollman*/
9812708Swollman
9822708Swollmanstatic int
9832708Swollmantzparse(name, sp, lastditch)
9842708Swollmanconst char *			name;
98592889Sobrienstruct state * const	sp;
9862708Swollmanconst int			lastditch;
9872708Swollman{
9882708Swollman	const char *			stdname;
9892708Swollman	const char *			dstname;
9909936Swollman	size_t				stdlen;
9919936Swollman	size_t				dstlen;
9922708Swollman	long				stdoffset;
9932708Swollman	long				dstoffset;
99492889Sobrien	time_t *		atp;
99592889Sobrien	unsigned char *	typep;
99692889Sobrien	char *			cp;
99792889Sobrien	int			load_result;
9982708Swollman
9999936Swollman	INITIALIZE(dstname);
10002708Swollman	stdname = name;
10012708Swollman	if (lastditch) {
10022708Swollman		stdlen = strlen(name);	/* length of standard zone name */
10032708Swollman		name += stdlen;
10042708Swollman		if (stdlen >= sizeof sp->chars)
10052708Swollman			stdlen = (sizeof sp->chars) - 1;
100621659Swollman		stdoffset = 0;
10072708Swollman	} else {
1008192625Sedwin		if (*name == '<') {
1009192625Sedwin			name++;
1010192625Sedwin			stdname = name;
1011192625Sedwin			name = getqzname(name, '>');
1012192625Sedwin			if (*name != '>')
1013192625Sedwin				return (-1);
1014192625Sedwin			stdlen = name - stdname;
1015192625Sedwin			name++;
1016192625Sedwin		} else {
1017192625Sedwin			name = getzname(name);
1018192625Sedwin			stdlen = name - stdname;
1019192625Sedwin		}
102021659Swollman		if (*name == '\0')
102121659Swollman			return -1;	/* was "stdoffset = 0;" */
102221659Swollman		else {
102321659Swollman			name = getoffset(name, &stdoffset);
102421659Swollman			if (name == NULL)
102521659Swollman				return -1;
102621659Swollman		}
10272708Swollman	}
1028192625Sedwin	load_result = tzload(TZDEFRULES, sp, FALSE);
10292708Swollman	if (load_result != 0)
10302708Swollman		sp->leapcnt = 0;		/* so, we're off a little */
10312708Swollman	if (*name != '\0') {
1032192625Sedwin		if (*name == '<') {
1033192625Sedwin			dstname = ++name;
1034192625Sedwin			name = getqzname(name, '>');
1035192625Sedwin			if (*name != '>')
1036192625Sedwin				return -1;
1037192625Sedwin			dstlen = name - dstname;
1038192625Sedwin			name++;
1039192625Sedwin		} else {
1040192625Sedwin			dstname = name;
1041192625Sedwin			name = getzname(name);
1042192625Sedwin			dstlen = name - dstname; /* length of DST zone name */
1043192625Sedwin		}
10442708Swollman		if (*name != '\0' && *name != ',' && *name != ';') {
10452708Swollman			name = getoffset(name, &dstoffset);
10462708Swollman			if (name == NULL)
10472708Swollman				return -1;
10482708Swollman		} else	dstoffset = stdoffset - SECSPERHOUR;
1049130461Sstefanf		if (*name == '\0' && load_result != 0)
1050130461Sstefanf			name = TZDEFRULESTRING;
10512708Swollman		if (*name == ',' || *name == ';') {
10522708Swollman			struct rule	start;
10532708Swollman			struct rule	end;
105492889Sobrien			int	year;
105592889Sobrien			time_t	janfirst;
10562708Swollman			time_t		starttime;
10572708Swollman			time_t		endtime;
10582708Swollman
10592708Swollman			++name;
10602708Swollman			if ((name = getrule(name, &start)) == NULL)
10612708Swollman				return -1;
10622708Swollman			if (*name++ != ',')
10632708Swollman				return -1;
10642708Swollman			if ((name = getrule(name, &end)) == NULL)
10652708Swollman				return -1;
10662708Swollman			if (*name != '\0')
10672708Swollman				return -1;
10682708Swollman			sp->typecnt = 2;	/* standard time and DST */
10692708Swollman			/*
1070192625Sedwin			** Two transitions per year, from EPOCH_YEAR forward.
10712708Swollman			*/
10722708Swollman			sp->ttis[0].tt_gmtoff = -dstoffset;
10732708Swollman			sp->ttis[0].tt_isdst = 1;
10742708Swollman			sp->ttis[0].tt_abbrind = stdlen + 1;
10752708Swollman			sp->ttis[1].tt_gmtoff = -stdoffset;
10762708Swollman			sp->ttis[1].tt_isdst = 0;
10772708Swollman			sp->ttis[1].tt_abbrind = 0;
10782708Swollman			atp = sp->ats;
10792708Swollman			typep = sp->types;
10802708Swollman			janfirst = 0;
1081192625Sedwin			sp->timecnt = 0;
1082192625Sedwin			for (year = EPOCH_YEAR;
1083192625Sedwin			    sp->timecnt + 2 <= TZ_MAX_TIMES;
1084192625Sedwin			    ++year) {
1085192625Sedwin			    	time_t	newfirst;
1086192625Sedwin
10872708Swollman				starttime = transtime(janfirst, year, &start,
10882708Swollman					stdoffset);
10892708Swollman				endtime = transtime(janfirst, year, &end,
10902708Swollman					dstoffset);
10912708Swollman				if (starttime > endtime) {
10922708Swollman					*atp++ = endtime;
10932708Swollman					*typep++ = 1;	/* DST ends */
10942708Swollman					*atp++ = starttime;
10952708Swollman					*typep++ = 0;	/* DST begins */
10962708Swollman				} else {
10972708Swollman					*atp++ = starttime;
10982708Swollman					*typep++ = 0;	/* DST begins */
10992708Swollman					*atp++ = endtime;
11002708Swollman					*typep++ = 1;	/* DST ends */
11012708Swollman				}
1102192625Sedwin				sp->timecnt += 2;
1103192625Sedwin				newfirst = janfirst;
1104192625Sedwin				newfirst += year_lengths[isleap(year)] *
11052708Swollman					SECSPERDAY;
1106192625Sedwin				if (newfirst <= janfirst)
1107192625Sedwin					break;
1108192625Sedwin				janfirst = newfirst;
11092708Swollman			}
11102708Swollman		} else {
111192889Sobrien			long	theirstdoffset;
111292889Sobrien			long	theirdstoffset;
111392889Sobrien			long	theiroffset;
111492889Sobrien			int	isdst;
111592889Sobrien			int	i;
111692889Sobrien			int	j;
11172708Swollman
11182708Swollman			if (*name != '\0')
11192708Swollman				return -1;
11202708Swollman			/*
11219936Swollman			** Initial values of theirstdoffset and theirdstoffset.
11222708Swollman			*/
11239936Swollman			theirstdoffset = 0;
11249936Swollman			for (i = 0; i < sp->timecnt; ++i) {
11259936Swollman				j = sp->types[i];
11269936Swollman				if (!sp->ttis[j].tt_isdst) {
112717209Swollman					theirstdoffset =
112817209Swollman						-sp->ttis[j].tt_gmtoff;
11299936Swollman					break;
11302708Swollman				}
11312708Swollman			}
11329936Swollman			theirdstoffset = 0;
11339936Swollman			for (i = 0; i < sp->timecnt; ++i) {
11349936Swollman				j = sp->types[i];
11359936Swollman				if (sp->ttis[j].tt_isdst) {
113617209Swollman					theirdstoffset =
113717209Swollman						-sp->ttis[j].tt_gmtoff;
11389936Swollman					break;
11399936Swollman				}
11409936Swollman			}
11412708Swollman			/*
11429936Swollman			** Initially we're assumed to be in standard time.
11432708Swollman			*/
11449936Swollman			isdst = FALSE;
11459936Swollman			theiroffset = theirstdoffset;
11462708Swollman			/*
11479936Swollman			** Now juggle transition times and types
11489936Swollman			** tracking offsets as you do.
11492708Swollman			*/
11502708Swollman			for (i = 0; i < sp->timecnt; ++i) {
11519936Swollman				j = sp->types[i];
11529936Swollman				sp->types[i] = sp->ttis[j].tt_isdst;
11539936Swollman				if (sp->ttis[j].tt_ttisgmt) {
11549936Swollman					/* No adjustment to transition time */
11559936Swollman				} else {
11569936Swollman					/*
11579936Swollman					** If summer time is in effect, and the
11589936Swollman					** transition time was not specified as
11599936Swollman					** standard time, add the summer time
11609936Swollman					** offset to the transition time;
11619936Swollman					** otherwise, add the standard time
11629936Swollman					** offset to the transition time.
11639936Swollman					*/
11649936Swollman					/*
11659936Swollman					** Transitions from DST to DDST
11669936Swollman					** will effectively disappear since
11679936Swollman					** POSIX provides for only one DST
11689936Swollman					** offset.
11699936Swollman					*/
11709936Swollman					if (isdst && !sp->ttis[j].tt_ttisstd) {
11719936Swollman						sp->ats[i] += dstoffset -
11729936Swollman							theirdstoffset;
11739936Swollman					} else {
11749936Swollman						sp->ats[i] += stdoffset -
11759936Swollman							theirstdoffset;
11769936Swollman					}
11779936Swollman				}
11789936Swollman				theiroffset = -sp->ttis[j].tt_gmtoff;
11799936Swollman				if (sp->ttis[j].tt_isdst)
11809936Swollman					theirdstoffset = theiroffset;
11819936Swollman				else	theirstdoffset = theiroffset;
11822708Swollman			}
11839936Swollman			/*
11849936Swollman			** Finally, fill in ttis.
11859936Swollman			** ttisstd and ttisgmt need not be handled.
11869936Swollman			*/
11879936Swollman			sp->ttis[0].tt_gmtoff = -stdoffset;
11889936Swollman			sp->ttis[0].tt_isdst = FALSE;
11899936Swollman			sp->ttis[0].tt_abbrind = 0;
11909936Swollman			sp->ttis[1].tt_gmtoff = -dstoffset;
11919936Swollman			sp->ttis[1].tt_isdst = TRUE;
11929936Swollman			sp->ttis[1].tt_abbrind = stdlen + 1;
1193130461Sstefanf			sp->typecnt = 2;
11942708Swollman		}
11952708Swollman	} else {
11962708Swollman		dstlen = 0;
11972708Swollman		sp->typecnt = 1;		/* only standard time */
11982708Swollman		sp->timecnt = 0;
11992708Swollman		sp->ttis[0].tt_gmtoff = -stdoffset;
12002708Swollman		sp->ttis[0].tt_isdst = 0;
12012708Swollman		sp->ttis[0].tt_abbrind = 0;
12022708Swollman	}
12032708Swollman	sp->charcnt = stdlen + 1;
12042708Swollman	if (dstlen != 0)
12052708Swollman		sp->charcnt += dstlen + 1;
1206130461Sstefanf	if ((size_t) sp->charcnt > sizeof sp->chars)
12072708Swollman		return -1;
12082708Swollman	cp = sp->chars;
12092708Swollman	(void) strncpy(cp, stdname, stdlen);
12102708Swollman	cp += stdlen;
12112708Swollman	*cp++ = '\0';
12122708Swollman	if (dstlen != 0) {
12132708Swollman		(void) strncpy(cp, dstname, dstlen);
12142708Swollman		*(cp + dstlen) = '\0';
12152708Swollman	}
12162708Swollman	return 0;
12172708Swollman}
12182708Swollman
12192708Swollmanstatic void
12202708Swollmangmtload(sp)
12212708Swollmanstruct state * const	sp;
12222708Swollman{
1223192625Sedwin	if (tzload(gmt, sp, TRUE) != 0)
12249936Swollman		(void) tzparse(gmt, sp, TRUE);
12252708Swollman}
12262708Swollman
122771579Sdeischenstatic void
1228177824Sdavidxutzsetwall_basic(int rdlocked)
12292708Swollman{
1230177824Sdavidxu	if (!rdlocked)
1231177824Sdavidxu		_RWLOCK_RDLOCK(&lcl_rwlock);
1232177824Sdavidxu	if (lcl_is_set < 0) {
1233177824Sdavidxu		if (!rdlocked)
1234177824Sdavidxu			_RWLOCK_UNLOCK(&lcl_rwlock);
12359936Swollman		return;
1236177824Sdavidxu	}
1237177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
1238177824Sdavidxu
1239177824Sdavidxu	_RWLOCK_WRLOCK(&lcl_rwlock);
12409936Swollman	lcl_is_set = -1;
12419936Swollman
12422708Swollman#ifdef ALL_STATE
12432708Swollman	if (lclptr == NULL) {
1244214411Sedwin		lclptr = (struct state *) calloc(1, sizeof *lclptr);
12452708Swollman		if (lclptr == NULL) {
12462708Swollman			settzname();	/* all we can do */
1247177824Sdavidxu			_RWLOCK_UNLOCK(&lcl_rwlock);
1248177824Sdavidxu			if (rdlocked)
1249177824Sdavidxu				_RWLOCK_RDLOCK(&lcl_rwlock);
12502708Swollman			return;
12512708Swollman		}
12522708Swollman	}
12532708Swollman#endif /* defined ALL_STATE */
1254192625Sedwin	if (tzload((char *) NULL, lclptr, TRUE) != 0)
12552708Swollman		gmtload(lclptr);
12562708Swollman	settzname();
1257177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
1258177824Sdavidxu
1259177824Sdavidxu	if (rdlocked)
1260177824Sdavidxu		_RWLOCK_RDLOCK(&lcl_rwlock);
12612708Swollman}
12622708Swollman
12632708Swollmanvoid
126497423Salfredtzsetwall(void)
126513545Sjulian{
1266177824Sdavidxu	tzsetwall_basic(0);
126713545Sjulian}
126813545Sjulian
126913545Sjulianstatic void
1270177824Sdavidxutzset_basic(int rdlocked)
12712708Swollman{
127292889Sobrien	const char *	name;
12732708Swollman
12742708Swollman	name = getenv("TZ");
12752708Swollman	if (name == NULL) {
1276177824Sdavidxu		tzsetwall_basic(rdlocked);
12772708Swollman		return;
12782708Swollman	}
12799936Swollman
1280177824Sdavidxu	if (!rdlocked)
1281177824Sdavidxu		_RWLOCK_RDLOCK(&lcl_rwlock);
1282177824Sdavidxu	if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) {
1283177824Sdavidxu		if (!rdlocked)
1284177824Sdavidxu			_RWLOCK_UNLOCK(&lcl_rwlock);
12859936Swollman		return;
1286177824Sdavidxu	}
1287177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
1288177824Sdavidxu
1289177824Sdavidxu	_RWLOCK_WRLOCK(&lcl_rwlock);
1290130461Sstefanf	lcl_is_set = strlen(name) < sizeof lcl_TZname;
12919936Swollman	if (lcl_is_set)
12929936Swollman		(void) strcpy(lcl_TZname, name);
12939936Swollman
12942708Swollman#ifdef ALL_STATE
12952708Swollman	if (lclptr == NULL) {
1296214411Sedwin		lclptr = (struct state *) calloc(1, sizeof *lclptr);
12972708Swollman		if (lclptr == NULL) {
12982708Swollman			settzname();	/* all we can do */
1299177824Sdavidxu			_RWLOCK_UNLOCK(&lcl_rwlock);
1300177824Sdavidxu			if (rdlocked)
1301177824Sdavidxu				_RWLOCK_RDLOCK(&lcl_rwlock);
13022708Swollman			return;
13032708Swollman		}
13042708Swollman	}
13052708Swollman#endif /* defined ALL_STATE */
13062708Swollman	if (*name == '\0') {
13072708Swollman		/*
13082708Swollman		** User wants it fast rather than right.
13092708Swollman		*/
13102708Swollman		lclptr->leapcnt = 0;		/* so, we're off a little */
13112708Swollman		lclptr->timecnt = 0;
1312130461Sstefanf		lclptr->typecnt = 0;
1313130461Sstefanf		lclptr->ttis[0].tt_isdst = 0;
13142708Swollman		lclptr->ttis[0].tt_gmtoff = 0;
13152708Swollman		lclptr->ttis[0].tt_abbrind = 0;
13169936Swollman		(void) strcpy(lclptr->chars, gmt);
1317192625Sedwin	} else if (tzload(name, lclptr, TRUE) != 0)
13182708Swollman		if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
13192708Swollman			(void) gmtload(lclptr);
13202708Swollman	settzname();
1321177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
1322177824Sdavidxu
1323177824Sdavidxu	if (rdlocked)
1324177824Sdavidxu		_RWLOCK_RDLOCK(&lcl_rwlock);
13252708Swollman}
13262708Swollman
132713545Sjulianvoid
132897423Salfredtzset(void)
132913545Sjulian{
1330177824Sdavidxu	tzset_basic(0);
133113545Sjulian}
133213545Sjulian
13332708Swollman/*
13342708Swollman** The easy way to behave "as if no library function calls" localtime
13352708Swollman** is to not call it--so we drop its guts into "localsub", which can be
1336192625Sedwin** freely called. (And no, the PANS doesn't require the above behavior--
13372708Swollman** but it *is* desirable.)
13382708Swollman**
13392708Swollman** The unused offset argument is for the benefit of mktime variants.
13402708Swollman*/
13412708Swollman
13422708Swollman/*ARGSUSED*/
1343192625Sedwinstatic struct tm *
13442708Swollmanlocalsub(timep, offset, tmp)
13452708Swollmanconst time_t * const	timep;
13462708Swollmanconst long		offset;
13472708Swollmanstruct tm * const	tmp;
13482708Swollman{
134992889Sobrien	struct state *		sp;
135092889Sobrien	const struct ttinfo *	ttisp;
135192889Sobrien	int			i;
1352192625Sedwin	struct tm *		result;
1353192625Sedwin	const time_t		t = *timep;
13542708Swollman
13552708Swollman	sp = lclptr;
13562708Swollman#ifdef ALL_STATE
1357192625Sedwin	if (sp == NULL)
1358192625Sedwin		return gmtsub(timep, offset, tmp);
1359192625Sedwin#endif /* defined ALL_STATE */
1360192625Sedwin	if ((sp->goback && t < sp->ats[0]) ||
1361192625Sedwin		(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1362192625Sedwin			time_t			newt = t;
1363192625Sedwin			register time_t		seconds;
1364192625Sedwin			register time_t		tcycles;
1365192625Sedwin			register int_fast64_t	icycles;
1366192625Sedwin
1367192625Sedwin			if (t < sp->ats[0])
1368192625Sedwin				seconds = sp->ats[0] - t;
1369192625Sedwin			else	seconds = t - sp->ats[sp->timecnt - 1];
1370192625Sedwin			--seconds;
1371192625Sedwin			tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1372192625Sedwin			++tcycles;
1373192625Sedwin			icycles = tcycles;
1374192625Sedwin			if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1375192625Sedwin				return NULL;
1376192625Sedwin			seconds = icycles;
1377192625Sedwin			seconds *= YEARSPERREPEAT;
1378192625Sedwin			seconds *= AVGSECSPERYEAR;
1379192625Sedwin			if (t < sp->ats[0])
1380192625Sedwin				newt += seconds;
1381192625Sedwin			else	newt -= seconds;
1382192625Sedwin			if (newt < sp->ats[0] ||
1383192625Sedwin				newt > sp->ats[sp->timecnt - 1])
1384192625Sedwin					return NULL;	/* "cannot happen" */
1385192625Sedwin			result = localsub(&newt, offset, tmp);
1386192625Sedwin			if (result == tmp) {
1387192625Sedwin				register time_t	newy;
1388192625Sedwin
1389192625Sedwin				newy = tmp->tm_year;
1390192625Sedwin				if (t < sp->ats[0])
1391192625Sedwin					newy -= icycles * YEARSPERREPEAT;
1392192625Sedwin				else	newy += icycles * YEARSPERREPEAT;
1393192625Sedwin				tmp->tm_year = newy;
1394192625Sedwin				if (tmp->tm_year != newy)
1395192625Sedwin					return NULL;
1396192625Sedwin			}
1397192625Sedwin			return result;
13982708Swollman	}
13992708Swollman	if (sp->timecnt == 0 || t < sp->ats[0]) {
14002708Swollman		i = 0;
14012708Swollman		while (sp->ttis[i].tt_isdst)
14022708Swollman			if (++i >= sp->typecnt) {
14032708Swollman				i = 0;
14042708Swollman				break;
14052708Swollman			}
14062708Swollman	} else {
1407192625Sedwin		register int	lo = 1;
1408192625Sedwin		register int	hi = sp->timecnt;
1409192625Sedwin
1410192625Sedwin		while (lo < hi) {
1411192625Sedwin			register int	mid = (lo + hi) >> 1;
1412192625Sedwin
1413192625Sedwin			if (t < sp->ats[mid])
1414192625Sedwin				hi = mid;
1415192625Sedwin			else	lo = mid + 1;
1416192625Sedwin		}
1417192625Sedwin		i = (int) sp->types[lo - 1];
14182708Swollman	}
14192708Swollman	ttisp = &sp->ttis[i];
14202708Swollman	/*
14212708Swollman	** To get (wrong) behavior that's compatible with System V Release 2.0
14222708Swollman	** you'd replace the statement below with
14232708Swollman	**	t += ttisp->tt_gmtoff;
14242708Swollman	**	timesub(&t, 0L, sp, tmp);
14252708Swollman	*/
1426192625Sedwin	result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
14272708Swollman	tmp->tm_isdst = ttisp->tt_isdst;
14289936Swollman	tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
14292708Swollman#ifdef TM_ZONE
14309936Swollman	tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
14312708Swollman#endif /* defined TM_ZONE */
1432192625Sedwin	return result;
14332708Swollman}
14342708Swollman
1435200797Sjhbstatic void
1436200797Sjhblocaltime_key_init(void)
1437200797Sjhb{
1438200797Sjhb
1439200797Sjhb	localtime_key_error = _pthread_key_create(&localtime_key, free);
1440200797Sjhb}
1441200797Sjhb
144219636Shsustruct tm *
14432708Swollmanlocaltime(timep)
14442708Swollmanconst time_t * const	timep;
14452708Swollman{
144613545Sjulian	struct tm *p_tm;
144713545Sjulian
144871579Sdeischen	if (__isthreaded != 0) {
1449201669Sjhb		_pthread_once(&localtime_once, localtime_key_init);
1450200797Sjhb		if (localtime_key_error != 0) {
1451200797Sjhb			errno = localtime_key_error;
1452200797Sjhb			return(NULL);
145313545Sjulian		}
145471579Sdeischen		p_tm = _pthread_getspecific(localtime_key);
145571579Sdeischen		if (p_tm == NULL) {
145671579Sdeischen			if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
145771579Sdeischen			    == NULL)
145871579Sdeischen				return(NULL);
145971579Sdeischen			_pthread_setspecific(localtime_key, p_tm);
146071579Sdeischen		}
1461177824Sdavidxu		_RWLOCK_RDLOCK(&lcl_rwlock);
1462177824Sdavidxu		tzset_basic(1);
1463314446Semaste		p_tm = localsub(timep, 0L, p_tm);
1464177824Sdavidxu		_RWLOCK_UNLOCK(&lcl_rwlock);
146571579Sdeischen	} else {
1466177824Sdavidxu		tzset_basic(0);
1467314446Semaste		p_tm = localsub(timep, 0L, &tm);
146813545Sjulian	}
1469314446Semaste	return(p_tm);
14702708Swollman}
14712708Swollman
14722708Swollman/*
1473130461Sstefanf** Re-entrant version of localtime.
1474130461Sstefanf*/
1475130461Sstefanf
1476130461Sstefanfstruct tm *
1477192625Sedwinlocaltime_r(timep, tmp)
1478130461Sstefanfconst time_t * const	timep;
1479192625Sedwinstruct tm *		tmp;
1480130461Sstefanf{
1481177824Sdavidxu	_RWLOCK_RDLOCK(&lcl_rwlock);
1482177824Sdavidxu	tzset_basic(1);
1483314446Semaste	tmp = localsub(timep, 0L, tmp);
1484177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
1485192625Sedwin	return tmp;
1486130461Sstefanf}
1487130461Sstefanf
1488199607Sjhbstatic void
1489199607Sjhbgmt_init(void)
1490199607Sjhb{
1491199607Sjhb
1492199607Sjhb#ifdef ALL_STATE
1493214411Sedwin	gmtptr = (struct state *) calloc(1, sizeof *gmtptr);
1494199607Sjhb	if (gmtptr != NULL)
1495199607Sjhb#endif /* defined ALL_STATE */
1496199607Sjhb		gmtload(gmtptr);
1497199607Sjhb}
1498199607Sjhb
1499130461Sstefanf/*
15002708Swollman** gmtsub is to gmtime as localsub is to localtime.
15012708Swollman*/
15022708Swollman
1503192625Sedwinstatic struct tm *
15042708Swollmangmtsub(timep, offset, tmp)
15052708Swollmanconst time_t * const	timep;
15062708Swollmanconst long		offset;
15072708Swollmanstruct tm * const	tmp;
15082708Swollman{
1509192625Sedwin	register struct tm *	result;
1510192625Sedwin
1511199607Sjhb	_once(&gmt_once, gmt_init);
1512192625Sedwin	result = timesub(timep, offset, gmtptr, tmp);
15132708Swollman#ifdef TM_ZONE
15142708Swollman	/*
15152708Swollman	** Could get fancy here and deliver something such as
1516130461Sstefanf	** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
15172708Swollman	** but this is no time for a treasure hunt.
15182708Swollman	*/
15192708Swollman	if (offset != 0)
15209936Swollman		tmp->TM_ZONE = wildabbr;
15212708Swollman	else {
15222708Swollman#ifdef ALL_STATE
15232708Swollman		if (gmtptr == NULL)
15249936Swollman			tmp->TM_ZONE = gmt;
15252708Swollman		else	tmp->TM_ZONE = gmtptr->chars;
15262708Swollman#endif /* defined ALL_STATE */
15272708Swollman#ifndef ALL_STATE
15282708Swollman		tmp->TM_ZONE = gmtptr->chars;
15292708Swollman#endif /* State Farm */
15302708Swollman	}
15312708Swollman#endif /* defined TM_ZONE */
1532192625Sedwin	return result;
15332708Swollman}
15342708Swollman
1535201270Sjhbstatic void
1536201270Sjhbgmtime_key_init(void)
1537201270Sjhb{
1538201270Sjhb
1539201270Sjhb	gmtime_key_error = _pthread_key_create(&gmtime_key, free);
1540201270Sjhb}
1541201270Sjhb
15422708Swollmanstruct tm *
15432708Swollmangmtime(timep)
15442708Swollmanconst time_t * const	timep;
15452708Swollman{
154613545Sjulian	struct tm *p_tm;
154713545Sjulian
154871579Sdeischen	if (__isthreaded != 0) {
1549201669Sjhb		_pthread_once(&gmtime_once, gmtime_key_init);
1550201270Sjhb		if (gmtime_key_error != 0) {
1551201270Sjhb			errno = gmtime_key_error;
1552201270Sjhb			return(NULL);
155313545Sjulian		}
155471579Sdeischen		/*
155571579Sdeischen		 * Changed to follow POSIX.1 threads standard, which
155671579Sdeischen		 * is what BSD currently has.
155771579Sdeischen		 */
155871579Sdeischen		if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
155971579Sdeischen			if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
156071579Sdeischen			    == NULL) {
156171579Sdeischen				return(NULL);
156271579Sdeischen			}
156371579Sdeischen			_pthread_setspecific(gmtime_key, p_tm);
156413545Sjulian		}
156571579Sdeischen		gmtsub(timep, 0L, p_tm);
156671579Sdeischen		return(p_tm);
156713545Sjulian	}
156871579Sdeischen	else {
156971579Sdeischen		gmtsub(timep, 0L, &tm);
157071579Sdeischen		return(&tm);
157171579Sdeischen	}
15722708Swollman}
15732708Swollman
1574130461Sstefanf/*
1575130461Sstefanf* Re-entrant version of gmtime.
1576130461Sstefanf*/
1577130461Sstefanf
157819636Shsustruct tm *
1579192625Sedwingmtime_r(timep, tmp)
1580130461Sstefanfconst time_t * const	timep;
1581192625Sedwinstruct tm *		tmp;
158213545Sjulian{
1583192625Sedwin	return gmtsub(timep, 0L, tmp);
158413545Sjulian}
158513545Sjulian
15862708Swollman#ifdef STD_INSPIRED
15872708Swollman
15882708Swollmanstruct tm *
15892708Swollmanofftime(timep, offset)
15902708Swollmanconst time_t * const	timep;
15912708Swollmanconst long		offset;
15922708Swollman{
1593192625Sedwin	return gmtsub(timep, offset, &tm);
15942708Swollman}
15952708Swollman
15962708Swollman#endif /* defined STD_INSPIRED */
15972708Swollman
1598192625Sedwin/*
1599192625Sedwin** Return the number of leap years through the end of the given year
1600192625Sedwin** where, to make the math easy, the answer for year zero is defined as zero.
1601192625Sedwin*/
1602192625Sedwin
1603192625Sedwinstatic int
1604192625Sedwinleaps_thru_end_of(y)
1605192625Sedwinregister const int	y;
1606192625Sedwin{
1607192625Sedwin	return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1608192625Sedwin		-(leaps_thru_end_of(-(y + 1)) + 1);
1609192625Sedwin}
1610192625Sedwin
1611192625Sedwinstatic struct tm *
16122708Swollmantimesub(timep, offset, sp, tmp)
16132708Swollmanconst time_t * const			timep;
16142708Swollmanconst long				offset;
161592889Sobrienconst struct state * const	sp;
161692889Sobrienstruct tm * const		tmp;
16172708Swollman{
161892889Sobrien	const struct lsinfo *	lp;
1619192625Sedwin	time_t			tdays;
1620192625Sedwin	int			idays;	/* unsigned would be so 2003 */
162192889Sobrien	long			rem;
1622192625Sedwin	int			y;
162392889Sobrien	const int *		ip;
162492889Sobrien	long			corr;
162592889Sobrien	int			hit;
162692889Sobrien	int			i;
16272708Swollman
16282708Swollman	corr = 0;
16292708Swollman	hit = 0;
16302708Swollman#ifdef ALL_STATE
16312708Swollman	i = (sp == NULL) ? 0 : sp->leapcnt;
16322708Swollman#endif /* defined ALL_STATE */
16332708Swollman#ifndef ALL_STATE
16342708Swollman	i = sp->leapcnt;
16352708Swollman#endif /* State Farm */
16362708Swollman	while (--i >= 0) {
16372708Swollman		lp = &sp->lsis[i];
16382708Swollman		if (*timep >= lp->ls_trans) {
16392708Swollman			if (*timep == lp->ls_trans) {
16402708Swollman				hit = ((i == 0 && lp->ls_corr > 0) ||
16412708Swollman					lp->ls_corr > sp->lsis[i - 1].ls_corr);
16422708Swollman				if (hit)
16432708Swollman					while (i > 0 &&
16442708Swollman						sp->lsis[i].ls_trans ==
16452708Swollman						sp->lsis[i - 1].ls_trans + 1 &&
16462708Swollman						sp->lsis[i].ls_corr ==
16472708Swollman						sp->lsis[i - 1].ls_corr + 1) {
16482708Swollman							++hit;
16492708Swollman							--i;
16502708Swollman					}
16512708Swollman			}
16522708Swollman			corr = lp->ls_corr;
16532708Swollman			break;
16542708Swollman		}
16552708Swollman	}
1656192625Sedwin	y = EPOCH_YEAR;
1657192625Sedwin	tdays = *timep / SECSPERDAY;
1658192625Sedwin	rem = *timep - tdays * SECSPERDAY;
1659192625Sedwin	while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1660192625Sedwin		int		newy;
1661192625Sedwin		register time_t	tdelta;
1662192625Sedwin		register int	idelta;
1663192625Sedwin		register int	leapdays;
1664192625Sedwin
1665192625Sedwin		tdelta = tdays / DAYSPERLYEAR;
1666192625Sedwin		idelta = tdelta;
1667192625Sedwin		if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
1668192625Sedwin			return NULL;
1669192625Sedwin		if (idelta == 0)
1670192625Sedwin			idelta = (tdays < 0) ? -1 : 1;
1671192625Sedwin		newy = y;
1672192625Sedwin		if (increment_overflow(&newy, idelta))
1673192625Sedwin			return NULL;
1674192625Sedwin		leapdays = leaps_thru_end_of(newy - 1) -
1675192625Sedwin			leaps_thru_end_of(y - 1);
1676192625Sedwin		tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1677192625Sedwin		tdays -= leapdays;
1678192625Sedwin		y = newy;
16792708Swollman	}
1680192625Sedwin	{
1681192625Sedwin		register long	seconds;
1682192625Sedwin
1683192625Sedwin		seconds = tdays * SECSPERDAY + 0.5;
1684192625Sedwin		tdays = seconds / SECSPERDAY;
1685192625Sedwin		rem += seconds - tdays * SECSPERDAY;
1686192625Sedwin	}
1687192625Sedwin	/*
1688192625Sedwin	** Given the range, we can now fearlessly cast...
1689192625Sedwin	*/
1690192625Sedwin	idays = tdays;
1691192625Sedwin	rem += offset - corr;
16922708Swollman	while (rem < 0) {
16932708Swollman		rem += SECSPERDAY;
1694192625Sedwin		--idays;
16952708Swollman	}
16962708Swollman	while (rem >= SECSPERDAY) {
16972708Swollman		rem -= SECSPERDAY;
1698192625Sedwin		++idays;
16992708Swollman	}
1700192625Sedwin	while (idays < 0) {
1701192625Sedwin		if (increment_overflow(&y, -1))
1702192625Sedwin			return NULL;
1703192625Sedwin		idays += year_lengths[isleap(y)];
1704192625Sedwin	}
1705192625Sedwin	while (idays >= year_lengths[isleap(y)]) {
1706192625Sedwin		idays -= year_lengths[isleap(y)];
1707192625Sedwin		if (increment_overflow(&y, 1))
1708192625Sedwin			return NULL;
1709192625Sedwin	}
1710192625Sedwin	tmp->tm_year = y;
1711192625Sedwin	if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1712192625Sedwin		return NULL;
1713192625Sedwin	tmp->tm_yday = idays;
1714192625Sedwin	/*
1715192625Sedwin	** The "extra" mods below avoid overflow problems.
1716192625Sedwin	*/
1717192625Sedwin	tmp->tm_wday = EPOCH_WDAY +
1718192625Sedwin		((y - EPOCH_YEAR) % DAYSPERWEEK) *
1719192625Sedwin		(DAYSPERNYEAR % DAYSPERWEEK) +
1720192625Sedwin		leaps_thru_end_of(y - 1) -
1721192625Sedwin		leaps_thru_end_of(EPOCH_YEAR - 1) +
1722192625Sedwin		idays;
1723192625Sedwin	tmp->tm_wday %= DAYSPERWEEK;
1724192625Sedwin	if (tmp->tm_wday < 0)
1725192625Sedwin		tmp->tm_wday += DAYSPERWEEK;
17262708Swollman	tmp->tm_hour = (int) (rem / SECSPERHOUR);
1727192625Sedwin	rem %= SECSPERHOUR;
17282708Swollman	tmp->tm_min = (int) (rem / SECSPERMIN);
172917209Swollman	/*
173017209Swollman	** A positive leap second requires a special
1731192625Sedwin	** representation. This uses "... ??:59:60" et seq.
173217209Swollman	*/
173317209Swollman	tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1734192625Sedwin	ip = mon_lengths[isleap(y)];
1735192625Sedwin	for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1736192625Sedwin		idays -= ip[tmp->tm_mon];
1737192625Sedwin	tmp->tm_mday = (int) (idays + 1);
17382708Swollman	tmp->tm_isdst = 0;
17392708Swollman#ifdef TM_GMTOFF
17402708Swollman	tmp->TM_GMTOFF = offset;
17412708Swollman#endif /* defined TM_GMTOFF */
1742192625Sedwin	return tmp;
17432708Swollman}
17442708Swollman
17452708Swollmanchar *
17462708Swollmanctime(timep)
17472708Swollmanconst time_t * const	timep;
17482708Swollman{
17499936Swollman/*
17509936Swollman** Section 4.12.3.2 of X3.159-1989 requires that
1751130461Sstefanf**	The ctime function converts the calendar time pointed to by timer
1752192625Sedwin**	to local time in the form of a string. It is equivalent to
17539936Swollman**		asctime(localtime(timer))
17549936Swollman*/
17552708Swollman	return asctime(localtime(timep));
17562708Swollman}
17572708Swollman
175835285Sphkchar *
175935285Sphkctime_r(timep, buf)
176035285Sphkconst time_t * const	timep;
1761130461Sstefanfchar *			buf;
176235285Sphk{
1763192625Sedwin	struct tm	mytm;
1764130461Sstefanf
1765192625Sedwin	return asctime_r(localtime_r(timep, &mytm), buf);
176635285Sphk}
176735285Sphk
17682708Swollman/*
17692708Swollman** Adapted from code provided by Robert Elz, who writes:
17702708Swollman**	The "best" way to do mktime I think is based on an idea of Bob
177117209Swollman**	Kridle's (so its said...) from a long time ago.
1772192625Sedwin**	It does a binary search of the time_t space. Since time_t's are
17732708Swollman**	just 32 bits, its a max of 32 iterations (even at 64 bits it
17742708Swollman**	would still be very reasonable).
17752708Swollman*/
17762708Swollman
17772708Swollman#ifndef WRONG
17782708Swollman#define WRONG	(-1)
17792708Swollman#endif /* !defined WRONG */
17802708Swollman
17812708Swollman/*
1782192625Sedwin** Simplified normalize logic courtesy Paul Eggert.
17832708Swollman*/
17842708Swollman
17852708Swollmanstatic int
17862708Swollmanincrement_overflow(number, delta)
17872708Swollmanint *	number;
17882708Swollmanint	delta;
17892708Swollman{
17909936Swollman	int	number0;
17918870Srgrimes
17922708Swollman	number0 = *number;
17932708Swollman	*number += delta;
1794275509Sngie	return (*number < number0) != (delta < 0);
17952708Swollman}
17962708Swollman
17972708Swollmanstatic int
1798192625Sedwinlong_increment_overflow(number, delta)
1799192625Sedwinlong *	number;
1800192625Sedwinint	delta;
1801192625Sedwin{
1802192625Sedwin	long	number0;
1803192625Sedwin
1804192625Sedwin	number0 = *number;
1805192625Sedwin	*number += delta;
1806275509Sngie	return (*number < number0) != (delta < 0);
1807192625Sedwin}
1808192625Sedwin
1809192625Sedwinstatic int
18102708Swollmannormalize_overflow(tensptr, unitsptr, base)
18112708Swollmanint * const	tensptr;
18122708Swollmanint * const	unitsptr;
18132708Swollmanconst int	base;
18142708Swollman{
181592889Sobrien	int	tensdelta;
18162708Swollman
18172708Swollman	tensdelta = (*unitsptr >= 0) ?
18182708Swollman		(*unitsptr / base) :
18192708Swollman		(-1 - (-1 - *unitsptr) / base);
18202708Swollman	*unitsptr -= tensdelta * base;
18212708Swollman	return increment_overflow(tensptr, tensdelta);
18222708Swollman}
18232708Swollman
18242708Swollmanstatic int
1825192625Sedwinlong_normalize_overflow(tensptr, unitsptr, base)
1826192625Sedwinlong * const	tensptr;
1827192625Sedwinint * const	unitsptr;
1828192625Sedwinconst int	base;
1829192625Sedwin{
1830192625Sedwin	register int	tensdelta;
1831192625Sedwin
1832192625Sedwin	tensdelta = (*unitsptr >= 0) ?
1833192625Sedwin		(*unitsptr / base) :
1834192625Sedwin		(-1 - (-1 - *unitsptr) / base);
1835192625Sedwin	*unitsptr -= tensdelta * base;
1836192625Sedwin	return long_increment_overflow(tensptr, tensdelta);
1837192625Sedwin}
1838192625Sedwin
1839192625Sedwinstatic int
18402708Swollmantmcomp(atmp, btmp)
184192889Sobrienconst struct tm * const atmp;
184292889Sobrienconst struct tm * const btmp;
18432708Swollman{
184492889Sobrien	int	result;
18452708Swollman
18462708Swollman	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
18472708Swollman		(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
18482708Swollman		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
18492708Swollman		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
18502708Swollman		(result = (atmp->tm_min - btmp->tm_min)) == 0)
18512708Swollman			result = atmp->tm_sec - btmp->tm_sec;
18522708Swollman	return result;
18532708Swollman}
18542708Swollman
18552708Swollmanstatic time_t
1856130461Sstefanftime2sub(tmp, funcp, offset, okayp, do_norm_secs)
18572708Swollmanstruct tm * const	tmp;
1858192625Sedwinstruct tm * (* const	funcp)(const time_t*, long, struct tm*);
18592708Swollmanconst long		offset;
18602708Swollmanint * const		okayp;
1861130461Sstefanfconst int		do_norm_secs;
18622708Swollman{
186392889Sobrien	const struct state *	sp;
186492889Sobrien	int			dir;
1865192625Sedwin	int			i, j;
186692889Sobrien	int			saved_seconds;
1867192625Sedwin	long			li;
1868192625Sedwin	time_t			lo;
1869192625Sedwin	time_t			hi;
1870192625Sedwin	long			y;
1871192625Sedwin	time_t			newt;
1872192625Sedwin	time_t			t;
1873192625Sedwin	struct tm		yourtm, mytm;
18742708Swollman
18752708Swollman	*okayp = FALSE;
18762708Swollman	yourtm = *tmp;
1877130461Sstefanf	if (do_norm_secs) {
1878130461Sstefanf		if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1879130461Sstefanf			SECSPERMIN))
1880130461Sstefanf				return WRONG;
1881130461Sstefanf	}
18822708Swollman	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
18832708Swollman		return WRONG;
18842708Swollman	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
18852708Swollman		return WRONG;
1886192625Sedwin	y = yourtm.tm_year;
1887192625Sedwin	if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
18882708Swollman		return WRONG;
18892708Swollman	/*
1890192625Sedwin	** Turn y into an actual year number for now.
18912708Swollman	** It is converted back to an offset from TM_YEAR_BASE later.
18922708Swollman	*/
1893192625Sedwin	if (long_increment_overflow(&y, TM_YEAR_BASE))
18942708Swollman		return WRONG;
18952708Swollman	while (yourtm.tm_mday <= 0) {
1896192625Sedwin		if (long_increment_overflow(&y, -1))
18972708Swollman			return WRONG;
1898192625Sedwin		li = y + (1 < yourtm.tm_mon);
1899192625Sedwin		yourtm.tm_mday += year_lengths[isleap(li)];
19002708Swollman	}
19012708Swollman	while (yourtm.tm_mday > DAYSPERLYEAR) {
1902192625Sedwin		li = y + (1 < yourtm.tm_mon);
1903192625Sedwin		yourtm.tm_mday -= year_lengths[isleap(li)];
1904192625Sedwin		if (long_increment_overflow(&y, 1))
19052708Swollman			return WRONG;
19062708Swollman	}
19072708Swollman	for ( ; ; ) {
1908192625Sedwin		i = mon_lengths[isleap(y)][yourtm.tm_mon];
19092708Swollman		if (yourtm.tm_mday <= i)
19102708Swollman			break;
19112708Swollman		yourtm.tm_mday -= i;
19122708Swollman		if (++yourtm.tm_mon >= MONSPERYEAR) {
19132708Swollman			yourtm.tm_mon = 0;
1914192625Sedwin			if (long_increment_overflow(&y, 1))
19152708Swollman				return WRONG;
19162708Swollman		}
19172708Swollman	}
1918192625Sedwin	if (long_increment_overflow(&y, -TM_YEAR_BASE))
19192708Swollman		return WRONG;
1920192625Sedwin	yourtm.tm_year = y;
1921192625Sedwin	if (yourtm.tm_year != y)
1922192625Sedwin		return WRONG;
1923134231Speter	/* Don't go below 1900 for POLA */
1924134231Speter	if (yourtm.tm_year < 0)
1925134231Speter		return WRONG;
192677785Swollman	if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
192777785Swollman		saved_seconds = 0;
1928192625Sedwin	else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
19292708Swollman		/*
19302708Swollman		** We can't set tm_sec to 0, because that might push the
19312708Swollman		** time below the minimum representable time.
19322708Swollman		** Set tm_sec to 59 instead.
19332708Swollman		** This assumes that the minimum representable time is
19342708Swollman		** not in the same minute that a leap second was deleted from,
19352708Swollman		** which is a safer assumption than using 58 would be.
19362708Swollman		*/
19372708Swollman		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
19382708Swollman			return WRONG;
19392708Swollman		saved_seconds = yourtm.tm_sec;
19402708Swollman		yourtm.tm_sec = SECSPERMIN - 1;
19412708Swollman	} else {
19422708Swollman		saved_seconds = yourtm.tm_sec;
19432708Swollman		yourtm.tm_sec = 0;
19442708Swollman	}
19452708Swollman	/*
1946192625Sedwin	** Do a binary search (this works whatever time_t's type is).
19472708Swollman	*/
1948192625Sedwin	if (!TYPE_SIGNED(time_t)) {
1949192625Sedwin		lo = 0;
1950192625Sedwin		hi = lo - 1;
1951192625Sedwin	} else if (!TYPE_INTEGRAL(time_t)) {
1952192625Sedwin		if (sizeof(time_t) > sizeof(float))
1953192625Sedwin			hi = (time_t) DBL_MAX;
1954192625Sedwin		else	hi = (time_t) FLT_MAX;
1955192625Sedwin		lo = -hi;
1956192625Sedwin	} else {
1957192625Sedwin		lo = 1;
1958192625Sedwin		for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
1959192625Sedwin			lo *= 2;
1960192625Sedwin		hi = -(lo + 1);
1961192625Sedwin	}
19622708Swollman	for ( ; ; ) {
1963192625Sedwin		t = lo / 2 + hi / 2;
1964192625Sedwin		if (t < lo)
1965192625Sedwin			t = lo;
1966192625Sedwin		else if (t > hi)
1967192625Sedwin			t = hi;
1968192625Sedwin		if ((*funcp)(&t, offset, &mytm) == NULL) {
1969192625Sedwin			/*
1970192625Sedwin			** Assume that t is too extreme to be represented in
1971192625Sedwin			** a struct tm; arrange things so that it is less
1972192625Sedwin			** extreme on the next pass.
1973192625Sedwin			*/
1974192625Sedwin			dir = (t > 0) ? 1 : -1;
1975192625Sedwin		} else	dir = tmcomp(&mytm, &yourtm);
19762708Swollman		if (dir != 0) {
1977192625Sedwin			if (t == lo) {
1978192625Sedwin				++t;
1979192625Sedwin				if (t <= lo)
1980192625Sedwin					return WRONG;
1981192625Sedwin				++lo;
1982192625Sedwin			} else if (t == hi) {
1983192625Sedwin				--t;
1984192625Sedwin				if (t >= hi)
1985192625Sedwin					return WRONG;
1986192625Sedwin				--hi;
1987192625Sedwin			}
1988192625Sedwin			if (lo > hi)
19892708Swollman				return WRONG;
1990192625Sedwin			if (dir > 0)
1991192625Sedwin				hi = t;
1992192625Sedwin			else	lo = t;
19932708Swollman			continue;
19942708Swollman		}
19952708Swollman		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
19962708Swollman			break;
19972708Swollman		/*
19982708Swollman		** Right time, wrong type.
19992708Swollman		** Hunt for right time, right type.
20002708Swollman		** It's okay to guess wrong since the guess
20012708Swollman		** gets checked.
20022708Swollman		*/
2003192625Sedwin		sp = (const struct state *)
2004192625Sedwin			((funcp == localsub) ? lclptr : gmtptr);
20052708Swollman#ifdef ALL_STATE
20062708Swollman		if (sp == NULL)
20072708Swollman			return WRONG;
20082708Swollman#endif /* defined ALL_STATE */
200917209Swollman		for (i = sp->typecnt - 1; i >= 0; --i) {
20102708Swollman			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
20112708Swollman				continue;
201217209Swollman			for (j = sp->typecnt - 1; j >= 0; --j) {
20132708Swollman				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
20142708Swollman					continue;
20152708Swollman				newt = t + sp->ttis[j].tt_gmtoff -
20162708Swollman					sp->ttis[i].tt_gmtoff;
2017192625Sedwin				if ((*funcp)(&newt, offset, &mytm) == NULL)
2018192625Sedwin					continue;
20192708Swollman				if (tmcomp(&mytm, &yourtm) != 0)
20202708Swollman					continue;
20212708Swollman				if (mytm.tm_isdst != yourtm.tm_isdst)
20222708Swollman					continue;
20232708Swollman				/*
20242708Swollman				** We have a match.
20252708Swollman				*/
20262708Swollman				t = newt;
20272708Swollman				goto label;
20282708Swollman			}
20292708Swollman		}
20302708Swollman		return WRONG;
20312708Swollman	}
20322708Swollmanlabel:
20332708Swollman	newt = t + saved_seconds;
20342708Swollman	if ((newt < t) != (saved_seconds < 0))
20352708Swollman		return WRONG;
20362708Swollman	t = newt;
2037192625Sedwin	if ((*funcp)(&t, offset, tmp))
2038192625Sedwin		*okayp = TRUE;
20392708Swollman	return t;
20402708Swollman}
20412708Swollman
20422708Swollmanstatic time_t
2043130461Sstefanftime2(tmp, funcp, offset, okayp)
2044130461Sstefanfstruct tm * const	tmp;
2045192625Sedwinstruct tm * (* const	funcp)(const time_t*, long, struct tm*);
2046130461Sstefanfconst long		offset;
2047130461Sstefanfint * const		okayp;
2048130461Sstefanf{
2049130461Sstefanf	time_t	t;
2050130461Sstefanf
2051130461Sstefanf	/*
2052130461Sstefanf	** First try without normalization of seconds
2053130461Sstefanf	** (in case tm_sec contains a value associated with a leap second).
2054130461Sstefanf	** If that fails, try with normalization of seconds.
2055130461Sstefanf	*/
2056130461Sstefanf	t = time2sub(tmp, funcp, offset, okayp, FALSE);
2057130461Sstefanf	return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
2058130461Sstefanf}
2059130461Sstefanf
2060130461Sstefanfstatic time_t
20612708Swollmantime1(tmp, funcp, offset)
20622708Swollmanstruct tm * const	tmp;
2063192625Sedwinstruct tm * (* const  funcp)(const time_t *, long, struct tm *);
20642708Swollmanconst long		offset;
20652708Swollman{
206692889Sobrien	time_t			t;
206792889Sobrien	const struct state *	sp;
206892889Sobrien	int			samei, otheri;
2069130461Sstefanf	int			sameind, otherind;
2070130461Sstefanf	int			i;
2071130461Sstefanf	int			nseen;
2072130461Sstefanf	int				seen[TZ_MAX_TYPES];
2073130461Sstefanf	int				types[TZ_MAX_TYPES];
20742708Swollman	int				okay;
20752708Swollman
2076214411Sedwin	if (tmp == NULL) {
2077214411Sedwin		errno = EINVAL;
2078214411Sedwin		return WRONG;
2079214411Sedwin	}
2080214411Sedwin
20812708Swollman	if (tmp->tm_isdst > 1)
20822708Swollman		tmp->tm_isdst = 1;
20832708Swollman	t = time2(tmp, funcp, offset, &okay);
20842708Swollman#ifdef PCTS
20852708Swollman	/*
2086192625Sedwin	** PCTS code courtesy Grant Sullivan.
20872708Swollman	*/
20882708Swollman	if (okay)
20892708Swollman		return t;
20902708Swollman	if (tmp->tm_isdst < 0)
20912708Swollman		tmp->tm_isdst = 0;	/* reset to std and try again */
20922708Swollman#endif /* defined PCTS */
20932708Swollman#ifndef PCTS
20942708Swollman	if (okay || tmp->tm_isdst < 0)
20952708Swollman		return t;
20962708Swollman#endif /* !defined PCTS */
20972708Swollman	/*
20982708Swollman	** We're supposed to assume that somebody took a time of one type
20992708Swollman	** and did some math on it that yielded a "struct tm" that's bad.
21002708Swollman	** We try to divine the type they started from and adjust to the
21012708Swollman	** type they need.
21022708Swollman	*/
2103192625Sedwin	sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
21042708Swollman#ifdef ALL_STATE
21052708Swollman	if (sp == NULL)
21062708Swollman		return WRONG;
21072708Swollman#endif /* defined ALL_STATE */
2108130461Sstefanf	for (i = 0; i < sp->typecnt; ++i)
2109130461Sstefanf		seen[i] = FALSE;
2110130461Sstefanf	nseen = 0;
2111130461Sstefanf	for (i = sp->timecnt - 1; i >= 0; --i)
2112130461Sstefanf		if (!seen[sp->types[i]]) {
2113130461Sstefanf			seen[sp->types[i]] = TRUE;
2114130461Sstefanf			types[nseen++] = sp->types[i];
2115130461Sstefanf		}
2116130461Sstefanf	for (sameind = 0; sameind < nseen; ++sameind) {
2117130461Sstefanf		samei = types[sameind];
21182708Swollman		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
21192708Swollman			continue;
2120130461Sstefanf		for (otherind = 0; otherind < nseen; ++otherind) {
2121130461Sstefanf			otheri = types[otherind];
21222708Swollman			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
21232708Swollman				continue;
21242708Swollman			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
21252708Swollman					sp->ttis[samei].tt_gmtoff;
21262708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
21272708Swollman			t = time2(tmp, funcp, offset, &okay);
21282708Swollman			if (okay)
21292708Swollman				return t;
21302708Swollman			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
21312708Swollman					sp->ttis[samei].tt_gmtoff;
21322708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
21332708Swollman		}
21342708Swollman	}
21352708Swollman	return WRONG;
21362708Swollman}
21372708Swollman
21382708Swollmantime_t
21392708Swollmanmktime(tmp)
21402708Swollmanstruct tm * const	tmp;
21412708Swollman{
214213545Sjulian	time_t mktime_return_value;
2143177824Sdavidxu	_RWLOCK_RDLOCK(&lcl_rwlock);
2144177824Sdavidxu	tzset_basic(1);
214513545Sjulian	mktime_return_value = time1(tmp, localsub, 0L);
2146177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
214713545Sjulian	return(mktime_return_value);
21482708Swollman}
21492708Swollman
21502708Swollman#ifdef STD_INSPIRED
21512708Swollman
21522708Swollmantime_t
21532708Swollmantimelocal(tmp)
21542708Swollmanstruct tm * const	tmp;
21552708Swollman{
2156214411Sedwin	if (tmp != NULL)
2157214411Sedwin		tmp->tm_isdst = -1;	/* in case it wasn't initialized */
21582708Swollman	return mktime(tmp);
21592708Swollman}
21602708Swollman
21612708Swollmantime_t
21622708Swollmantimegm(tmp)
21632708Swollmanstruct tm * const	tmp;
21642708Swollman{
2165214411Sedwin	if (tmp != NULL)
2166214411Sedwin		tmp->tm_isdst = 0;
21672708Swollman	return time1(tmp, gmtsub, 0L);
21682708Swollman}
21692708Swollman
21702708Swollmantime_t
21712708Swollmantimeoff(tmp, offset)
21722708Swollmanstruct tm * const	tmp;
21732708Swollmanconst long		offset;
21742708Swollman{
2175214411Sedwin	if (tmp != NULL)
2176214411Sedwin		tmp->tm_isdst = 0;
21772708Swollman	return time1(tmp, gmtsub, offset);
21782708Swollman}
21792708Swollman
21802708Swollman#endif /* defined STD_INSPIRED */
21812708Swollman
21822708Swollman#ifdef CMUCS
21832708Swollman
21842708Swollman/*
21852708Swollman** The following is supplied for compatibility with
21862708Swollman** previous versions of the CMUCS runtime library.
21872708Swollman*/
21882708Swollman
21892708Swollmanlong
21902708Swollmangtime(tmp)
21912708Swollmanstruct tm * const	tmp;
21922708Swollman{
21932708Swollman	const time_t	t = mktime(tmp);
21942708Swollman
21952708Swollman	if (t == WRONG)
21962708Swollman		return -1;
21972708Swollman	return t;
21982708Swollman}
21992708Swollman
22002708Swollman#endif /* defined CMUCS */
22012708Swollman
22022708Swollman/*
22032708Swollman** XXX--is the below the right way to conditionalize??
22042708Swollman*/
22052708Swollman
22062708Swollman#ifdef STD_INSPIRED
22072708Swollman
22082708Swollman/*
22092708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2210130461Sstefanf** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
22112708Swollman** is not the case if we are accounting for leap seconds.
22122708Swollman** So, we provide the following conversion routines for use
22132708Swollman** when exchanging timestamps with POSIX conforming systems.
22142708Swollman*/
22152708Swollman
22162708Swollmanstatic long
22172708Swollmanleapcorr(timep)
22182708Swollmantime_t *	timep;
22192708Swollman{
222092889Sobrien	struct state *		sp;
222192889Sobrien	struct lsinfo *	lp;
222292889Sobrien	int			i;
22232708Swollman
22242708Swollman	sp = lclptr;
22252708Swollman	i = sp->leapcnt;
22262708Swollman	while (--i >= 0) {
22272708Swollman		lp = &sp->lsis[i];
22282708Swollman		if (*timep >= lp->ls_trans)
22292708Swollman			return lp->ls_corr;
22302708Swollman	}
22312708Swollman	return 0;
22322708Swollman}
22332708Swollman
22342708Swollmantime_t
22352708Swollmantime2posix(t)
22362708Swollmantime_t	t;
22372708Swollman{
22389936Swollman	tzset();
22392708Swollman	return t - leapcorr(&t);
22402708Swollman}
22412708Swollman
22422708Swollmantime_t
22432708Swollmanposix2time(t)
22442708Swollmantime_t	t;
22452708Swollman{
22462708Swollman	time_t	x;
22472708Swollman	time_t	y;
22482708Swollman
22499936Swollman	tzset();
22502708Swollman	/*
22512708Swollman	** For a positive leap second hit, the result
2252192625Sedwin	** is not unique. For a negative leap second
22532708Swollman	** hit, the corresponding time doesn't exist,
22542708Swollman	** so we return an adjacent second.
22552708Swollman	*/
22562708Swollman	x = t + leapcorr(&t);
22572708Swollman	y = x - leapcorr(&x);
22582708Swollman	if (y < t) {
22592708Swollman		do {
22602708Swollman			x++;
22612708Swollman			y = x - leapcorr(&x);
22622708Swollman		} while (y < t);
22632708Swollman		if (t != y)
22642708Swollman			return x - 1;
22652708Swollman	} else if (y > t) {
22662708Swollman		do {
22672708Swollman			--x;
22682708Swollman			y = x - leapcorr(&x);
22692708Swollman		} while (y > t);
22702708Swollman		if (t != y)
22712708Swollman			return x + 1;
22722708Swollman	}
22732708Swollman	return x;
22742708Swollman}
22752708Swollman
22762708Swollman#endif /* defined STD_INSPIRED */
2277