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$");
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		}
453226929Strociny		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);
146371579Sdeischen		localsub(timep, 0L, p_tm);
1464177824Sdavidxu		_RWLOCK_UNLOCK(&lcl_rwlock);
146571579Sdeischen		return(p_tm);
146671579Sdeischen	} else {
1467177824Sdavidxu		tzset_basic(0);
146871579Sdeischen		localsub(timep, 0L, &tm);
146971579Sdeischen		return(&tm);
147013545Sjulian	}
14712708Swollman}
14722708Swollman
14732708Swollman/*
1474130461Sstefanf** Re-entrant version of localtime.
1475130461Sstefanf*/
1476130461Sstefanf
1477130461Sstefanfstruct tm *
1478192625Sedwinlocaltime_r(timep, tmp)
1479130461Sstefanfconst time_t * const	timep;
1480192625Sedwinstruct tm *		tmp;
1481130461Sstefanf{
1482177824Sdavidxu	_RWLOCK_RDLOCK(&lcl_rwlock);
1483177824Sdavidxu	tzset_basic(1);
1484192625Sedwin	localsub(timep, 0L, tmp);
1485177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
1486192625Sedwin	return tmp;
1487130461Sstefanf}
1488130461Sstefanf
1489199607Sjhbstatic void
1490199607Sjhbgmt_init(void)
1491199607Sjhb{
1492199607Sjhb
1493199607Sjhb#ifdef ALL_STATE
1494214411Sedwin	gmtptr = (struct state *) calloc(1, sizeof *gmtptr);
1495199607Sjhb	if (gmtptr != NULL)
1496199607Sjhb#endif /* defined ALL_STATE */
1497199607Sjhb		gmtload(gmtptr);
1498199607Sjhb}
1499199607Sjhb
1500130461Sstefanf/*
15012708Swollman** gmtsub is to gmtime as localsub is to localtime.
15022708Swollman*/
15032708Swollman
1504192625Sedwinstatic struct tm *
15052708Swollmangmtsub(timep, offset, tmp)
15062708Swollmanconst time_t * const	timep;
15072708Swollmanconst long		offset;
15082708Swollmanstruct tm * const	tmp;
15092708Swollman{
1510192625Sedwin	register struct tm *	result;
1511192625Sedwin
1512199607Sjhb	_once(&gmt_once, gmt_init);
1513192625Sedwin	result = timesub(timep, offset, gmtptr, tmp);
15142708Swollman#ifdef TM_ZONE
15152708Swollman	/*
15162708Swollman	** Could get fancy here and deliver something such as
1517130461Sstefanf	** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
15182708Swollman	** but this is no time for a treasure hunt.
15192708Swollman	*/
15202708Swollman	if (offset != 0)
15219936Swollman		tmp->TM_ZONE = wildabbr;
15222708Swollman	else {
15232708Swollman#ifdef ALL_STATE
15242708Swollman		if (gmtptr == NULL)
15259936Swollman			tmp->TM_ZONE = gmt;
15262708Swollman		else	tmp->TM_ZONE = gmtptr->chars;
15272708Swollman#endif /* defined ALL_STATE */
15282708Swollman#ifndef ALL_STATE
15292708Swollman		tmp->TM_ZONE = gmtptr->chars;
15302708Swollman#endif /* State Farm */
15312708Swollman	}
15322708Swollman#endif /* defined TM_ZONE */
1533192625Sedwin	return result;
15342708Swollman}
15352708Swollman
1536201270Sjhbstatic void
1537201270Sjhbgmtime_key_init(void)
1538201270Sjhb{
1539201270Sjhb
1540201270Sjhb	gmtime_key_error = _pthread_key_create(&gmtime_key, free);
1541201270Sjhb}
1542201270Sjhb
15432708Swollmanstruct tm *
15442708Swollmangmtime(timep)
15452708Swollmanconst time_t * const	timep;
15462708Swollman{
154713545Sjulian	struct tm *p_tm;
154813545Sjulian
154971579Sdeischen	if (__isthreaded != 0) {
1550201669Sjhb		_pthread_once(&gmtime_once, gmtime_key_init);
1551201270Sjhb		if (gmtime_key_error != 0) {
1552201270Sjhb			errno = gmtime_key_error;
1553201270Sjhb			return(NULL);
155413545Sjulian		}
155571579Sdeischen		/*
155671579Sdeischen		 * Changed to follow POSIX.1 threads standard, which
155771579Sdeischen		 * is what BSD currently has.
155871579Sdeischen		 */
155971579Sdeischen		if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
156071579Sdeischen			if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
156171579Sdeischen			    == NULL) {
156271579Sdeischen				return(NULL);
156371579Sdeischen			}
156471579Sdeischen			_pthread_setspecific(gmtime_key, p_tm);
156513545Sjulian		}
156671579Sdeischen		gmtsub(timep, 0L, p_tm);
156771579Sdeischen		return(p_tm);
156813545Sjulian	}
156971579Sdeischen	else {
157071579Sdeischen		gmtsub(timep, 0L, &tm);
157171579Sdeischen		return(&tm);
157271579Sdeischen	}
15732708Swollman}
15742708Swollman
1575130461Sstefanf/*
1576130461Sstefanf* Re-entrant version of gmtime.
1577130461Sstefanf*/
1578130461Sstefanf
157919636Shsustruct tm *
1580192625Sedwingmtime_r(timep, tmp)
1581130461Sstefanfconst time_t * const	timep;
1582192625Sedwinstruct tm *		tmp;
158313545Sjulian{
1584192625Sedwin	return gmtsub(timep, 0L, tmp);
158513545Sjulian}
158613545Sjulian
15872708Swollman#ifdef STD_INSPIRED
15882708Swollman
15892708Swollmanstruct tm *
15902708Swollmanofftime(timep, offset)
15912708Swollmanconst time_t * const	timep;
15922708Swollmanconst long		offset;
15932708Swollman{
1594192625Sedwin	return gmtsub(timep, offset, &tm);
15952708Swollman}
15962708Swollman
15972708Swollman#endif /* defined STD_INSPIRED */
15982708Swollman
1599192625Sedwin/*
1600192625Sedwin** Return the number of leap years through the end of the given year
1601192625Sedwin** where, to make the math easy, the answer for year zero is defined as zero.
1602192625Sedwin*/
1603192625Sedwin
1604192625Sedwinstatic int
1605192625Sedwinleaps_thru_end_of(y)
1606192625Sedwinregister const int	y;
1607192625Sedwin{
1608192625Sedwin	return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1609192625Sedwin		-(leaps_thru_end_of(-(y + 1)) + 1);
1610192625Sedwin}
1611192625Sedwin
1612192625Sedwinstatic struct tm *
16132708Swollmantimesub(timep, offset, sp, tmp)
16142708Swollmanconst time_t * const			timep;
16152708Swollmanconst long				offset;
161692889Sobrienconst struct state * const	sp;
161792889Sobrienstruct tm * const		tmp;
16182708Swollman{
161992889Sobrien	const struct lsinfo *	lp;
1620192625Sedwin	time_t			tdays;
1621192625Sedwin	int			idays;	/* unsigned would be so 2003 */
162292889Sobrien	long			rem;
1623192625Sedwin	int			y;
162492889Sobrien	const int *		ip;
162592889Sobrien	long			corr;
162692889Sobrien	int			hit;
162792889Sobrien	int			i;
16282708Swollman
16292708Swollman	corr = 0;
16302708Swollman	hit = 0;
16312708Swollman#ifdef ALL_STATE
16322708Swollman	i = (sp == NULL) ? 0 : sp->leapcnt;
16332708Swollman#endif /* defined ALL_STATE */
16342708Swollman#ifndef ALL_STATE
16352708Swollman	i = sp->leapcnt;
16362708Swollman#endif /* State Farm */
16372708Swollman	while (--i >= 0) {
16382708Swollman		lp = &sp->lsis[i];
16392708Swollman		if (*timep >= lp->ls_trans) {
16402708Swollman			if (*timep == lp->ls_trans) {
16412708Swollman				hit = ((i == 0 && lp->ls_corr > 0) ||
16422708Swollman					lp->ls_corr > sp->lsis[i - 1].ls_corr);
16432708Swollman				if (hit)
16442708Swollman					while (i > 0 &&
16452708Swollman						sp->lsis[i].ls_trans ==
16462708Swollman						sp->lsis[i - 1].ls_trans + 1 &&
16472708Swollman						sp->lsis[i].ls_corr ==
16482708Swollman						sp->lsis[i - 1].ls_corr + 1) {
16492708Swollman							++hit;
16502708Swollman							--i;
16512708Swollman					}
16522708Swollman			}
16532708Swollman			corr = lp->ls_corr;
16542708Swollman			break;
16552708Swollman		}
16562708Swollman	}
1657192625Sedwin	y = EPOCH_YEAR;
1658192625Sedwin	tdays = *timep / SECSPERDAY;
1659192625Sedwin	rem = *timep - tdays * SECSPERDAY;
1660192625Sedwin	while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1661192625Sedwin		int		newy;
1662192625Sedwin		register time_t	tdelta;
1663192625Sedwin		register int	idelta;
1664192625Sedwin		register int	leapdays;
1665192625Sedwin
1666192625Sedwin		tdelta = tdays / DAYSPERLYEAR;
1667192625Sedwin		idelta = tdelta;
1668192625Sedwin		if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
1669192625Sedwin			return NULL;
1670192625Sedwin		if (idelta == 0)
1671192625Sedwin			idelta = (tdays < 0) ? -1 : 1;
1672192625Sedwin		newy = y;
1673192625Sedwin		if (increment_overflow(&newy, idelta))
1674192625Sedwin			return NULL;
1675192625Sedwin		leapdays = leaps_thru_end_of(newy - 1) -
1676192625Sedwin			leaps_thru_end_of(y - 1);
1677192625Sedwin		tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1678192625Sedwin		tdays -= leapdays;
1679192625Sedwin		y = newy;
16802708Swollman	}
1681192625Sedwin	{
1682192625Sedwin		register long	seconds;
1683192625Sedwin
1684192625Sedwin		seconds = tdays * SECSPERDAY + 0.5;
1685192625Sedwin		tdays = seconds / SECSPERDAY;
1686192625Sedwin		rem += seconds - tdays * SECSPERDAY;
1687192625Sedwin	}
1688192625Sedwin	/*
1689192625Sedwin	** Given the range, we can now fearlessly cast...
1690192625Sedwin	*/
1691192625Sedwin	idays = tdays;
1692192625Sedwin	rem += offset - corr;
16932708Swollman	while (rem < 0) {
16942708Swollman		rem += SECSPERDAY;
1695192625Sedwin		--idays;
16962708Swollman	}
16972708Swollman	while (rem >= SECSPERDAY) {
16982708Swollman		rem -= SECSPERDAY;
1699192625Sedwin		++idays;
17002708Swollman	}
1701192625Sedwin	while (idays < 0) {
1702192625Sedwin		if (increment_overflow(&y, -1))
1703192625Sedwin			return NULL;
1704192625Sedwin		idays += year_lengths[isleap(y)];
1705192625Sedwin	}
1706192625Sedwin	while (idays >= year_lengths[isleap(y)]) {
1707192625Sedwin		idays -= year_lengths[isleap(y)];
1708192625Sedwin		if (increment_overflow(&y, 1))
1709192625Sedwin			return NULL;
1710192625Sedwin	}
1711192625Sedwin	tmp->tm_year = y;
1712192625Sedwin	if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1713192625Sedwin		return NULL;
1714192625Sedwin	tmp->tm_yday = idays;
1715192625Sedwin	/*
1716192625Sedwin	** The "extra" mods below avoid overflow problems.
1717192625Sedwin	*/
1718192625Sedwin	tmp->tm_wday = EPOCH_WDAY +
1719192625Sedwin		((y - EPOCH_YEAR) % DAYSPERWEEK) *
1720192625Sedwin		(DAYSPERNYEAR % DAYSPERWEEK) +
1721192625Sedwin		leaps_thru_end_of(y - 1) -
1722192625Sedwin		leaps_thru_end_of(EPOCH_YEAR - 1) +
1723192625Sedwin		idays;
1724192625Sedwin	tmp->tm_wday %= DAYSPERWEEK;
1725192625Sedwin	if (tmp->tm_wday < 0)
1726192625Sedwin		tmp->tm_wday += DAYSPERWEEK;
17272708Swollman	tmp->tm_hour = (int) (rem / SECSPERHOUR);
1728192625Sedwin	rem %= SECSPERHOUR;
17292708Swollman	tmp->tm_min = (int) (rem / SECSPERMIN);
173017209Swollman	/*
173117209Swollman	** A positive leap second requires a special
1732192625Sedwin	** representation. This uses "... ??:59:60" et seq.
173317209Swollman	*/
173417209Swollman	tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1735192625Sedwin	ip = mon_lengths[isleap(y)];
1736192625Sedwin	for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1737192625Sedwin		idays -= ip[tmp->tm_mon];
1738192625Sedwin	tmp->tm_mday = (int) (idays + 1);
17392708Swollman	tmp->tm_isdst = 0;
17402708Swollman#ifdef TM_GMTOFF
17412708Swollman	tmp->TM_GMTOFF = offset;
17422708Swollman#endif /* defined TM_GMTOFF */
1743192625Sedwin	return tmp;
17442708Swollman}
17452708Swollman
17462708Swollmanchar *
17472708Swollmanctime(timep)
17482708Swollmanconst time_t * const	timep;
17492708Swollman{
17509936Swollman/*
17519936Swollman** Section 4.12.3.2 of X3.159-1989 requires that
1752130461Sstefanf**	The ctime function converts the calendar time pointed to by timer
1753192625Sedwin**	to local time in the form of a string. It is equivalent to
17549936Swollman**		asctime(localtime(timer))
17559936Swollman*/
17562708Swollman	return asctime(localtime(timep));
17572708Swollman}
17582708Swollman
175935285Sphkchar *
176035285Sphkctime_r(timep, buf)
176135285Sphkconst time_t * const	timep;
1762130461Sstefanfchar *			buf;
176335285Sphk{
1764192625Sedwin	struct tm	mytm;
1765130461Sstefanf
1766192625Sedwin	return asctime_r(localtime_r(timep, &mytm), buf);
176735285Sphk}
176835285Sphk
17692708Swollman/*
17702708Swollman** Adapted from code provided by Robert Elz, who writes:
17712708Swollman**	The "best" way to do mktime I think is based on an idea of Bob
177217209Swollman**	Kridle's (so its said...) from a long time ago.
1773192625Sedwin**	It does a binary search of the time_t space. Since time_t's are
17742708Swollman**	just 32 bits, its a max of 32 iterations (even at 64 bits it
17752708Swollman**	would still be very reasonable).
17762708Swollman*/
17772708Swollman
17782708Swollman#ifndef WRONG
17792708Swollman#define WRONG	(-1)
17802708Swollman#endif /* !defined WRONG */
17812708Swollman
17822708Swollman/*
1783192625Sedwin** Simplified normalize logic courtesy Paul Eggert.
17842708Swollman*/
17852708Swollman
17862708Swollmanstatic int
17872708Swollmanincrement_overflow(number, delta)
17882708Swollmanint *	number;
17892708Swollmanint	delta;
17902708Swollman{
17919936Swollman	int	number0;
17928870Srgrimes
17932708Swollman	number0 = *number;
17942708Swollman	*number += delta;
17952708Swollman	return (*number < number0) != (delta < 0);
17962708Swollman}
17972708Swollman
17982708Swollmanstatic int
1799192625Sedwinlong_increment_overflow(number, delta)
1800192625Sedwinlong *	number;
1801192625Sedwinint	delta;
1802192625Sedwin{
1803192625Sedwin	long	number0;
1804192625Sedwin
1805192625Sedwin	number0 = *number;
1806192625Sedwin	*number += delta;
1807192625Sedwin	return (*number < number0) != (delta < 0);
1808192625Sedwin}
1809192625Sedwin
1810192625Sedwinstatic int
18112708Swollmannormalize_overflow(tensptr, unitsptr, base)
18122708Swollmanint * const	tensptr;
18132708Swollmanint * const	unitsptr;
18142708Swollmanconst int	base;
18152708Swollman{
181692889Sobrien	int	tensdelta;
18172708Swollman
18182708Swollman	tensdelta = (*unitsptr >= 0) ?
18192708Swollman		(*unitsptr / base) :
18202708Swollman		(-1 - (-1 - *unitsptr) / base);
18212708Swollman	*unitsptr -= tensdelta * base;
18222708Swollman	return increment_overflow(tensptr, tensdelta);
18232708Swollman}
18242708Swollman
18252708Swollmanstatic int
1826192625Sedwinlong_normalize_overflow(tensptr, unitsptr, base)
1827192625Sedwinlong * const	tensptr;
1828192625Sedwinint * const	unitsptr;
1829192625Sedwinconst int	base;
1830192625Sedwin{
1831192625Sedwin	register int	tensdelta;
1832192625Sedwin
1833192625Sedwin	tensdelta = (*unitsptr >= 0) ?
1834192625Sedwin		(*unitsptr / base) :
1835192625Sedwin		(-1 - (-1 - *unitsptr) / base);
1836192625Sedwin	*unitsptr -= tensdelta * base;
1837192625Sedwin	return long_increment_overflow(tensptr, tensdelta);
1838192625Sedwin}
1839192625Sedwin
1840192625Sedwinstatic int
18412708Swollmantmcomp(atmp, btmp)
184292889Sobrienconst struct tm * const atmp;
184392889Sobrienconst struct tm * const btmp;
18442708Swollman{
184592889Sobrien	int	result;
18462708Swollman
18472708Swollman	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
18482708Swollman		(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
18492708Swollman		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
18502708Swollman		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
18512708Swollman		(result = (atmp->tm_min - btmp->tm_min)) == 0)
18522708Swollman			result = atmp->tm_sec - btmp->tm_sec;
18532708Swollman	return result;
18542708Swollman}
18552708Swollman
18562708Swollmanstatic time_t
1857130461Sstefanftime2sub(tmp, funcp, offset, okayp, do_norm_secs)
18582708Swollmanstruct tm * const	tmp;
1859192625Sedwinstruct tm * (* const	funcp)(const time_t*, long, struct tm*);
18602708Swollmanconst long		offset;
18612708Swollmanint * const		okayp;
1862130461Sstefanfconst int		do_norm_secs;
18632708Swollman{
186492889Sobrien	const struct state *	sp;
186592889Sobrien	int			dir;
1866192625Sedwin	int			i, j;
186792889Sobrien	int			saved_seconds;
1868192625Sedwin	long			li;
1869192625Sedwin	time_t			lo;
1870192625Sedwin	time_t			hi;
1871192625Sedwin	long			y;
1872192625Sedwin	time_t			newt;
1873192625Sedwin	time_t			t;
1874192625Sedwin	struct tm		yourtm, mytm;
18752708Swollman
18762708Swollman	*okayp = FALSE;
18772708Swollman	yourtm = *tmp;
1878130461Sstefanf	if (do_norm_secs) {
1879130461Sstefanf		if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1880130461Sstefanf			SECSPERMIN))
1881130461Sstefanf				return WRONG;
1882130461Sstefanf	}
18832708Swollman	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
18842708Swollman		return WRONG;
18852708Swollman	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
18862708Swollman		return WRONG;
1887192625Sedwin	y = yourtm.tm_year;
1888192625Sedwin	if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
18892708Swollman		return WRONG;
18902708Swollman	/*
1891192625Sedwin	** Turn y into an actual year number for now.
18922708Swollman	** It is converted back to an offset from TM_YEAR_BASE later.
18932708Swollman	*/
1894192625Sedwin	if (long_increment_overflow(&y, TM_YEAR_BASE))
18952708Swollman		return WRONG;
18962708Swollman	while (yourtm.tm_mday <= 0) {
1897192625Sedwin		if (long_increment_overflow(&y, -1))
18982708Swollman			return WRONG;
1899192625Sedwin		li = y + (1 < yourtm.tm_mon);
1900192625Sedwin		yourtm.tm_mday += year_lengths[isleap(li)];
19012708Swollman	}
19022708Swollman	while (yourtm.tm_mday > DAYSPERLYEAR) {
1903192625Sedwin		li = y + (1 < yourtm.tm_mon);
1904192625Sedwin		yourtm.tm_mday -= year_lengths[isleap(li)];
1905192625Sedwin		if (long_increment_overflow(&y, 1))
19062708Swollman			return WRONG;
19072708Swollman	}
19082708Swollman	for ( ; ; ) {
1909192625Sedwin		i = mon_lengths[isleap(y)][yourtm.tm_mon];
19102708Swollman		if (yourtm.tm_mday <= i)
19112708Swollman			break;
19122708Swollman		yourtm.tm_mday -= i;
19132708Swollman		if (++yourtm.tm_mon >= MONSPERYEAR) {
19142708Swollman			yourtm.tm_mon = 0;
1915192625Sedwin			if (long_increment_overflow(&y, 1))
19162708Swollman				return WRONG;
19172708Swollman		}
19182708Swollman	}
1919192625Sedwin	if (long_increment_overflow(&y, -TM_YEAR_BASE))
19202708Swollman		return WRONG;
1921192625Sedwin	yourtm.tm_year = y;
1922192625Sedwin	if (yourtm.tm_year != y)
1923192625Sedwin		return WRONG;
1924134231Speter	/* Don't go below 1900 for POLA */
1925134231Speter	if (yourtm.tm_year < 0)
1926134231Speter		return WRONG;
192777785Swollman	if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
192877785Swollman		saved_seconds = 0;
1929192625Sedwin	else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
19302708Swollman		/*
19312708Swollman		** We can't set tm_sec to 0, because that might push the
19322708Swollman		** time below the minimum representable time.
19332708Swollman		** Set tm_sec to 59 instead.
19342708Swollman		** This assumes that the minimum representable time is
19352708Swollman		** not in the same minute that a leap second was deleted from,
19362708Swollman		** which is a safer assumption than using 58 would be.
19372708Swollman		*/
19382708Swollman		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
19392708Swollman			return WRONG;
19402708Swollman		saved_seconds = yourtm.tm_sec;
19412708Swollman		yourtm.tm_sec = SECSPERMIN - 1;
19422708Swollman	} else {
19432708Swollman		saved_seconds = yourtm.tm_sec;
19442708Swollman		yourtm.tm_sec = 0;
19452708Swollman	}
19462708Swollman	/*
1947192625Sedwin	** Do a binary search (this works whatever time_t's type is).
19482708Swollman	*/
1949192625Sedwin	if (!TYPE_SIGNED(time_t)) {
1950192625Sedwin		lo = 0;
1951192625Sedwin		hi = lo - 1;
1952192625Sedwin	} else if (!TYPE_INTEGRAL(time_t)) {
1953192625Sedwin		if (sizeof(time_t) > sizeof(float))
1954192625Sedwin			hi = (time_t) DBL_MAX;
1955192625Sedwin		else	hi = (time_t) FLT_MAX;
1956192625Sedwin		lo = -hi;
1957192625Sedwin	} else {
1958192625Sedwin		lo = 1;
1959192625Sedwin		for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
1960192625Sedwin			lo *= 2;
1961192625Sedwin		hi = -(lo + 1);
1962192625Sedwin	}
19632708Swollman	for ( ; ; ) {
1964192625Sedwin		t = lo / 2 + hi / 2;
1965192625Sedwin		if (t < lo)
1966192625Sedwin			t = lo;
1967192625Sedwin		else if (t > hi)
1968192625Sedwin			t = hi;
1969192625Sedwin		if ((*funcp)(&t, offset, &mytm) == NULL) {
1970192625Sedwin			/*
1971192625Sedwin			** Assume that t is too extreme to be represented in
1972192625Sedwin			** a struct tm; arrange things so that it is less
1973192625Sedwin			** extreme on the next pass.
1974192625Sedwin			*/
1975192625Sedwin			dir = (t > 0) ? 1 : -1;
1976192625Sedwin		} else	dir = tmcomp(&mytm, &yourtm);
19772708Swollman		if (dir != 0) {
1978192625Sedwin			if (t == lo) {
1979192625Sedwin				++t;
1980192625Sedwin				if (t <= lo)
1981192625Sedwin					return WRONG;
1982192625Sedwin				++lo;
1983192625Sedwin			} else if (t == hi) {
1984192625Sedwin				--t;
1985192625Sedwin				if (t >= hi)
1986192625Sedwin					return WRONG;
1987192625Sedwin				--hi;
1988192625Sedwin			}
1989192625Sedwin			if (lo > hi)
19902708Swollman				return WRONG;
1991192625Sedwin			if (dir > 0)
1992192625Sedwin				hi = t;
1993192625Sedwin			else	lo = t;
19942708Swollman			continue;
19952708Swollman		}
19962708Swollman		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
19972708Swollman			break;
19982708Swollman		/*
19992708Swollman		** Right time, wrong type.
20002708Swollman		** Hunt for right time, right type.
20012708Swollman		** It's okay to guess wrong since the guess
20022708Swollman		** gets checked.
20032708Swollman		*/
2004192625Sedwin		sp = (const struct state *)
2005192625Sedwin			((funcp == localsub) ? lclptr : gmtptr);
20062708Swollman#ifdef ALL_STATE
20072708Swollman		if (sp == NULL)
20082708Swollman			return WRONG;
20092708Swollman#endif /* defined ALL_STATE */
201017209Swollman		for (i = sp->typecnt - 1; i >= 0; --i) {
20112708Swollman			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
20122708Swollman				continue;
201317209Swollman			for (j = sp->typecnt - 1; j >= 0; --j) {
20142708Swollman				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
20152708Swollman					continue;
20162708Swollman				newt = t + sp->ttis[j].tt_gmtoff -
20172708Swollman					sp->ttis[i].tt_gmtoff;
2018192625Sedwin				if ((*funcp)(&newt, offset, &mytm) == NULL)
2019192625Sedwin					continue;
20202708Swollman				if (tmcomp(&mytm, &yourtm) != 0)
20212708Swollman					continue;
20222708Swollman				if (mytm.tm_isdst != yourtm.tm_isdst)
20232708Swollman					continue;
20242708Swollman				/*
20252708Swollman				** We have a match.
20262708Swollman				*/
20272708Swollman				t = newt;
20282708Swollman				goto label;
20292708Swollman			}
20302708Swollman		}
20312708Swollman		return WRONG;
20322708Swollman	}
20332708Swollmanlabel:
20342708Swollman	newt = t + saved_seconds;
20352708Swollman	if ((newt < t) != (saved_seconds < 0))
20362708Swollman		return WRONG;
20372708Swollman	t = newt;
2038192625Sedwin	if ((*funcp)(&t, offset, tmp))
2039192625Sedwin		*okayp = TRUE;
20402708Swollman	return t;
20412708Swollman}
20422708Swollman
20432708Swollmanstatic time_t
2044130461Sstefanftime2(tmp, funcp, offset, okayp)
2045130461Sstefanfstruct tm * const	tmp;
2046192625Sedwinstruct tm * (* const	funcp)(const time_t*, long, struct tm*);
2047130461Sstefanfconst long		offset;
2048130461Sstefanfint * const		okayp;
2049130461Sstefanf{
2050130461Sstefanf	time_t	t;
2051130461Sstefanf
2052130461Sstefanf	/*
2053130461Sstefanf	** First try without normalization of seconds
2054130461Sstefanf	** (in case tm_sec contains a value associated with a leap second).
2055130461Sstefanf	** If that fails, try with normalization of seconds.
2056130461Sstefanf	*/
2057130461Sstefanf	t = time2sub(tmp, funcp, offset, okayp, FALSE);
2058130461Sstefanf	return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
2059130461Sstefanf}
2060130461Sstefanf
2061130461Sstefanfstatic time_t
20622708Swollmantime1(tmp, funcp, offset)
20632708Swollmanstruct tm * const	tmp;
2064192625Sedwinstruct tm * (* const  funcp)(const time_t *, long, struct tm *);
20652708Swollmanconst long		offset;
20662708Swollman{
206792889Sobrien	time_t			t;
206892889Sobrien	const struct state *	sp;
206992889Sobrien	int			samei, otheri;
2070130461Sstefanf	int			sameind, otherind;
2071130461Sstefanf	int			i;
2072130461Sstefanf	int			nseen;
2073130461Sstefanf	int				seen[TZ_MAX_TYPES];
2074130461Sstefanf	int				types[TZ_MAX_TYPES];
20752708Swollman	int				okay;
20762708Swollman
2077214411Sedwin	if (tmp == NULL) {
2078214411Sedwin		errno = EINVAL;
2079214411Sedwin		return WRONG;
2080214411Sedwin	}
2081214411Sedwin
20822708Swollman	if (tmp->tm_isdst > 1)
20832708Swollman		tmp->tm_isdst = 1;
20842708Swollman	t = time2(tmp, funcp, offset, &okay);
20852708Swollman#ifdef PCTS
20862708Swollman	/*
2087192625Sedwin	** PCTS code courtesy Grant Sullivan.
20882708Swollman	*/
20892708Swollman	if (okay)
20902708Swollman		return t;
20912708Swollman	if (tmp->tm_isdst < 0)
20922708Swollman		tmp->tm_isdst = 0;	/* reset to std and try again */
20932708Swollman#endif /* defined PCTS */
20942708Swollman#ifndef PCTS
20952708Swollman	if (okay || tmp->tm_isdst < 0)
20962708Swollman		return t;
20972708Swollman#endif /* !defined PCTS */
20982708Swollman	/*
20992708Swollman	** We're supposed to assume that somebody took a time of one type
21002708Swollman	** and did some math on it that yielded a "struct tm" that's bad.
21012708Swollman	** We try to divine the type they started from and adjust to the
21022708Swollman	** type they need.
21032708Swollman	*/
2104192625Sedwin	sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
21052708Swollman#ifdef ALL_STATE
21062708Swollman	if (sp == NULL)
21072708Swollman		return WRONG;
21082708Swollman#endif /* defined ALL_STATE */
2109130461Sstefanf	for (i = 0; i < sp->typecnt; ++i)
2110130461Sstefanf		seen[i] = FALSE;
2111130461Sstefanf	nseen = 0;
2112130461Sstefanf	for (i = sp->timecnt - 1; i >= 0; --i)
2113130461Sstefanf		if (!seen[sp->types[i]]) {
2114130461Sstefanf			seen[sp->types[i]] = TRUE;
2115130461Sstefanf			types[nseen++] = sp->types[i];
2116130461Sstefanf		}
2117130461Sstefanf	for (sameind = 0; sameind < nseen; ++sameind) {
2118130461Sstefanf		samei = types[sameind];
21192708Swollman		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
21202708Swollman			continue;
2121130461Sstefanf		for (otherind = 0; otherind < nseen; ++otherind) {
2122130461Sstefanf			otheri = types[otherind];
21232708Swollman			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
21242708Swollman				continue;
21252708Swollman			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
21262708Swollman					sp->ttis[samei].tt_gmtoff;
21272708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
21282708Swollman			t = time2(tmp, funcp, offset, &okay);
21292708Swollman			if (okay)
21302708Swollman				return t;
21312708Swollman			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
21322708Swollman					sp->ttis[samei].tt_gmtoff;
21332708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
21342708Swollman		}
21352708Swollman	}
21362708Swollman	return WRONG;
21372708Swollman}
21382708Swollman
21392708Swollmantime_t
21402708Swollmanmktime(tmp)
21412708Swollmanstruct tm * const	tmp;
21422708Swollman{
214313545Sjulian	time_t mktime_return_value;
2144177824Sdavidxu	_RWLOCK_RDLOCK(&lcl_rwlock);
2145177824Sdavidxu	tzset_basic(1);
214613545Sjulian	mktime_return_value = time1(tmp, localsub, 0L);
2147177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
214813545Sjulian	return(mktime_return_value);
21492708Swollman}
21502708Swollman
21512708Swollman#ifdef STD_INSPIRED
21522708Swollman
21532708Swollmantime_t
21542708Swollmantimelocal(tmp)
21552708Swollmanstruct tm * const	tmp;
21562708Swollman{
2157214411Sedwin	if (tmp != NULL)
2158214411Sedwin		tmp->tm_isdst = -1;	/* in case it wasn't initialized */
21592708Swollman	return mktime(tmp);
21602708Swollman}
21612708Swollman
21622708Swollmantime_t
21632708Swollmantimegm(tmp)
21642708Swollmanstruct tm * const	tmp;
21652708Swollman{
2166214411Sedwin	if (tmp != NULL)
2167214411Sedwin		tmp->tm_isdst = 0;
21682708Swollman	return time1(tmp, gmtsub, 0L);
21692708Swollman}
21702708Swollman
21712708Swollmantime_t
21722708Swollmantimeoff(tmp, offset)
21732708Swollmanstruct tm * const	tmp;
21742708Swollmanconst long		offset;
21752708Swollman{
2176214411Sedwin	if (tmp != NULL)
2177214411Sedwin		tmp->tm_isdst = 0;
21782708Swollman	return time1(tmp, gmtsub, offset);
21792708Swollman}
21802708Swollman
21812708Swollman#endif /* defined STD_INSPIRED */
21822708Swollman
21832708Swollman#ifdef CMUCS
21842708Swollman
21852708Swollman/*
21862708Swollman** The following is supplied for compatibility with
21872708Swollman** previous versions of the CMUCS runtime library.
21882708Swollman*/
21892708Swollman
21902708Swollmanlong
21912708Swollmangtime(tmp)
21922708Swollmanstruct tm * const	tmp;
21932708Swollman{
21942708Swollman	const time_t	t = mktime(tmp);
21952708Swollman
21962708Swollman	if (t == WRONG)
21972708Swollman		return -1;
21982708Swollman	return t;
21992708Swollman}
22002708Swollman
22012708Swollman#endif /* defined CMUCS */
22022708Swollman
22032708Swollman/*
22042708Swollman** XXX--is the below the right way to conditionalize??
22052708Swollman*/
22062708Swollman
22072708Swollman#ifdef STD_INSPIRED
22082708Swollman
22092708Swollman/*
22102708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2211130461Sstefanf** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
22122708Swollman** is not the case if we are accounting for leap seconds.
22132708Swollman** So, we provide the following conversion routines for use
22142708Swollman** when exchanging timestamps with POSIX conforming systems.
22152708Swollman*/
22162708Swollman
22172708Swollmanstatic long
22182708Swollmanleapcorr(timep)
22192708Swollmantime_t *	timep;
22202708Swollman{
222192889Sobrien	struct state *		sp;
222292889Sobrien	struct lsinfo *	lp;
222392889Sobrien	int			i;
22242708Swollman
22252708Swollman	sp = lclptr;
22262708Swollman	i = sp->leapcnt;
22272708Swollman	while (--i >= 0) {
22282708Swollman		lp = &sp->lsis[i];
22292708Swollman		if (*timep >= lp->ls_trans)
22302708Swollman			return lp->ls_corr;
22312708Swollman	}
22322708Swollman	return 0;
22332708Swollman}
22342708Swollman
22352708Swollmantime_t
22362708Swollmantime2posix(t)
22372708Swollmantime_t	t;
22382708Swollman{
22399936Swollman	tzset();
22402708Swollman	return t - leapcorr(&t);
22412708Swollman}
22422708Swollman
22432708Swollmantime_t
22442708Swollmanposix2time(t)
22452708Swollmantime_t	t;
22462708Swollman{
22472708Swollman	time_t	x;
22482708Swollman	time_t	y;
22492708Swollman
22509936Swollman	tzset();
22512708Swollman	/*
22522708Swollman	** For a positive leap second hit, the result
2253192625Sedwin	** is not unique. For a negative leap second
22542708Swollman	** hit, the corresponding time doesn't exist,
22552708Swollman	** so we return an adjacent second.
22562708Swollman	*/
22572708Swollman	x = t + leapcorr(&t);
22582708Swollman	y = x - leapcorr(&x);
22592708Swollman	if (y < t) {
22602708Swollman		do {
22612708Swollman			x++;
22622708Swollman			y = x - leapcorr(&x);
22632708Swollman		} while (y < t);
22642708Swollman		if (t != y)
22652708Swollman			return x - 1;
22662708Swollman	} else if (y > t) {
22672708Swollman		do {
22682708Swollman			--x;
22692708Swollman			y = x - leapcorr(&x);
22702708Swollman		} while (y > t);
22712708Swollman		if (t != y)
22722708Swollman			return x + 1;
22732708Swollman	}
22742708Swollman	return x;
22752708Swollman}
22762708Swollman
22772708Swollman#endif /* defined STD_INSPIRED */
2278