localtime.c revision 192625
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
9192625Sedwinstatic char	elsieid[] __unused = "@(#)localtime.c	8.9";
102708Swollman#endif /* !defined NOID */
112708Swollman#endif /* !defined lint */
1292986Sobrien__FBSDID("$FreeBSD: head/lib/libc/stdtime/localtime.c 192625 2009-05-23 06:31:50Z edwin $");
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>
2471579Sdeischen#include <fcntl.h>
2571579Sdeischen#include <pthread.h>
2671579Sdeischen#include "private.h"
2771579Sdeischen#include "un-namespace.h"
2818834Swollman
292708Swollman#include "tzfile.h"
30192625Sedwin#include "float.h"	/* for FLT_MAX and DBL_MAX */
312708Swollman
32192625Sedwin#ifndef TZ_ABBR_MAX_LEN
33192625Sedwin#define TZ_ABBR_MAX_LEN	16
34192625Sedwin#endif /* !defined TZ_ABBR_MAX_LEN */
35192625Sedwin
36192625Sedwin#ifndef TZ_ABBR_CHAR_SET
37192625Sedwin#define TZ_ABBR_CHAR_SET \
38192625Sedwin	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
39192625Sedwin#endif /* !defined TZ_ABBR_CHAR_SET */
40192625Sedwin
41192625Sedwin#ifndef TZ_ABBR_ERR_CHAR
42192625Sedwin#define TZ_ABBR_ERR_CHAR	'_'
43192625Sedwin#endif /* !defined TZ_ABBR_ERR_CHAR */
44192625Sedwin
4571579Sdeischen#include "libc_private.h"
4671579Sdeischen
4771579Sdeischen#define	_MUTEX_LOCK(x)		if (__isthreaded) _pthread_mutex_lock(x)
4871579Sdeischen#define	_MUTEX_UNLOCK(x)	if (__isthreaded) _pthread_mutex_unlock(x)
4971579Sdeischen
50177824Sdavidxu#define _RWLOCK_RDLOCK(x)						\
51177824Sdavidxu		do {							\
52177824Sdavidxu			if (__isthreaded) _pthread_rwlock_rdlock(x);	\
53177824Sdavidxu		} while (0)
54177824Sdavidxu
55177824Sdavidxu#define _RWLOCK_WRLOCK(x)						\
56177824Sdavidxu		do {							\
57177824Sdavidxu			if (__isthreaded) _pthread_rwlock_wrlock(x);	\
58177824Sdavidxu		} while (0)
59177824Sdavidxu
60177824Sdavidxu#define _RWLOCK_UNLOCK(x)						\
61177824Sdavidxu		do {							\
62177824Sdavidxu			if (__isthreaded) _pthread_rwlock_unlock(x);	\
63177824Sdavidxu		} while (0)
64177824Sdavidxu
659936Swollman/*
669936Swollman** SunOS 4.1.1 headers lack O_BINARY.
679936Swollman*/
682708Swollman
692708Swollman#ifdef O_BINARY
702708Swollman#define OPEN_MODE	(O_RDONLY | O_BINARY)
712708Swollman#endif /* defined O_BINARY */
722708Swollman#ifndef O_BINARY
732708Swollman#define OPEN_MODE	O_RDONLY
742708Swollman#endif /* !defined O_BINARY */
752708Swollman
762708Swollman#ifndef WILDABBR
772708Swollman/*
782708Swollman** Someone might make incorrect use of a time zone abbreviation:
792708Swollman**	1.	They might reference tzname[0] before calling tzset (explicitly
809936Swollman**		or implicitly).
812708Swollman**	2.	They might reference tzname[1] before calling tzset (explicitly
829936Swollman**		or implicitly).
832708Swollman**	3.	They might reference tzname[1] after setting to a time zone
842708Swollman**		in which Daylight Saving Time is never observed.
852708Swollman**	4.	They might reference tzname[0] after setting to a time zone
862708Swollman**		in which Standard Time is never observed.
872708Swollman**	5.	They might reference tm.TM_ZONE after calling offtime.
882708Swollman** What's best to do in the above cases is open to debate;
892708Swollman** for now, we just set things up so that in any of the five cases
90192625Sedwin** WILDABBR is used. Another possibility: initialize tzname[0] to the
912708Swollman** string "tzname[0] used before set", and similarly for the other cases.
92192625Sedwin** And another: initialize tzname[0] to "ERA", with an explanation in the
932708Swollman** manual page of what this "time zone abbreviation" means (doing this so
942708Swollman** that tzname[0] has the "normal" length of three characters).
952708Swollman*/
962708Swollman#define WILDABBR	"   "
972708Swollman#endif /* !defined WILDABBR */
982708Swollman
99192625Sedwinstatic char		wildabbr[] = WILDABBR;
1002708Swollman
101130332Skensmith/*
102130332Skensmith * In June 2004 it was decided UTC was a more appropriate default time
103130332Skensmith * zone than GMT.
104130332Skensmith */
1059936Swollman
106130332Skensmithstatic const char	gmt[] = "UTC";
107130332Skensmith
108130461Sstefanf/*
109130461Sstefanf** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
110130461Sstefanf** We default to US rules as of 1999-08-17.
111130461Sstefanf** POSIX 1003.1 section 8.1.1 says that the default DST rules are
112130461Sstefanf** implementation dependent; for historical reasons, US rules are a
113130461Sstefanf** common default.
114130461Sstefanf*/
115130461Sstefanf#ifndef TZDEFRULESTRING
116130461Sstefanf#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
117130461Sstefanf#endif /* !defined TZDEFDST */
118130461Sstefanf
1192708Swollmanstruct ttinfo {				/* time type information */
120130461Sstefanf	long		tt_gmtoff;	/* UTC offset in seconds */
1212708Swollman	int		tt_isdst;	/* used to set tm_isdst */
1222708Swollman	int		tt_abbrind;	/* abbreviation list index */
1232708Swollman	int		tt_ttisstd;	/* TRUE if transition is std time */
124130461Sstefanf	int		tt_ttisgmt;	/* TRUE if transition is UTC */
1252708Swollman};
1262708Swollman
1272708Swollmanstruct lsinfo {				/* leap second information */
1282708Swollman	time_t		ls_trans;	/* transition time */
1292708Swollman	long		ls_corr;	/* correction to apply */
1302708Swollman};
1312708Swollman
1322708Swollman#define BIGGEST(a, b)	(((a) > (b)) ? (a) : (b))
1332708Swollman
1342708Swollman#ifdef TZNAME_MAX
1352708Swollman#define MY_TZNAME_MAX	TZNAME_MAX
1362708Swollman#endif /* defined TZNAME_MAX */
1372708Swollman#ifndef TZNAME_MAX
1382708Swollman#define MY_TZNAME_MAX	255
1392708Swollman#endif /* !defined TZNAME_MAX */
1402708Swollman
1412708Swollmanstruct state {
1422708Swollman	int		leapcnt;
1432708Swollman	int		timecnt;
1442708Swollman	int		typecnt;
1452708Swollman	int		charcnt;
146192625Sedwin	int		goback;
147192625Sedwin	int		goahead;
1482708Swollman	time_t		ats[TZ_MAX_TIMES];
1492708Swollman	unsigned char	types[TZ_MAX_TIMES];
1502708Swollman	struct ttinfo	ttis[TZ_MAX_TYPES];
1519936Swollman	char		chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
1522708Swollman				(2 * (MY_TZNAME_MAX + 1)))];
1532708Swollman	struct lsinfo	lsis[TZ_MAX_LEAPS];
1542708Swollman};
1552708Swollman
1562708Swollmanstruct rule {
1572708Swollman	int		r_type;		/* type of rule--see below */
1582708Swollman	int		r_day;		/* day number of rule */
1592708Swollman	int		r_week;		/* week number of rule */
1602708Swollman	int		r_mon;		/* month number of rule */
1612708Swollman	long		r_time;		/* transition time of rule */
1622708Swollman};
1632708Swollman
1642708Swollman#define JULIAN_DAY		0	/* Jn - Julian day */
1652708Swollman#define DAY_OF_YEAR		1	/* n - day of year */
1662708Swollman#define MONTH_NTH_DAY_OF_WEEK	2	/* Mm.n.d - month, week, day of week */
1672708Swollman
1682708Swollman/*
1692708Swollman** Prototypes for static functions.
1702708Swollman*/
1712708Swollman
17297423Salfredstatic long		detzcode(const char * codep);
173192625Sedwinstatic time_t		detzcode64(const char * codep);
174192625Sedwinstatic int		differ_by_repeat(time_t t1, time_t t0);
17597423Salfredstatic const char *	getzname(const char * strp);
176192625Sedwinstatic const char *	getqzname(const char * strp, const int delim);
17797423Salfredstatic const char *	getnum(const char * strp, int * nump, int min,
17897423Salfred				int max);
17997423Salfredstatic const char *	getsecs(const char * strp, long * secsp);
18097423Salfredstatic const char *	getoffset(const char * strp, long * offsetp);
18197423Salfredstatic const char *	getrule(const char * strp, struct rule * rulep);
18297423Salfredstatic void		gmtload(struct state * sp);
183192625Sedwinstatic struct tm *	gmtsub(const time_t * timep, long offset,
18497423Salfred				struct tm * tmp);
185192625Sedwinstatic struct tm *	localsub(const time_t * timep, long offset,
18697423Salfred				struct tm * tmp);
18797423Salfredstatic int		increment_overflow(int * number, int delta);
188192625Sedwinstatic int		leaps_thru_end_of(int y);
189192625Sedwinstatic int		long_increment_overflow(long * number, int delta);
190192625Sedwinstatic int		long_normalize_overflow(long * tensptr,
191192625Sedwin				int * unitsptr, int base);
19297423Salfredstatic int		normalize_overflow(int * tensptr, int * unitsptr,
19397423Salfred				int base);
19497423Salfredstatic void		settzname(void);
19597423Salfredstatic time_t		time1(struct tm * tmp,
196192625Sedwin				struct tm * (*funcp)(const time_t *,
19797423Salfred				long, struct tm *),
19897423Salfred				long offset);
19997423Salfredstatic time_t		time2(struct tm *tmp,
200192625Sedwin				struct tm * (*funcp)(const time_t *,
20197423Salfred				long, struct tm*),
20297423Salfred				long offset, int * okayp);
203130461Sstefanfstatic time_t		time2sub(struct tm *tmp,
204192625Sedwin				struct tm * (*funcp)(const time_t *,
205130461Sstefanf				long, struct tm*),
206130461Sstefanf				long offset, int * okayp, int do_norm_secs);
207192625Sedwinstatic struct tm *	timesub(const time_t * timep, long offset,
20897423Salfred				const struct state * sp, struct tm * tmp);
20997423Salfredstatic int		tmcomp(const struct tm * atmp,
21097423Salfred				const struct tm * btmp);
21197423Salfredstatic time_t		transtime(time_t janfirst, int year,
21297423Salfred				const struct rule * rulep, long offset);
213192625Sedwinstatic int		typesequiv(const struct state * sp, int a, int b);
214192625Sedwinstatic int		tzload(const char * name, struct state * sp,
215192625Sedwin				int doextend);
21697423Salfredstatic int		tzparse(const char * name, struct state * sp,
21797423Salfred				int lastditch);
2182708Swollman
2192708Swollman#ifdef ALL_STATE
2202708Swollmanstatic struct state *	lclptr;
2212708Swollmanstatic struct state *	gmtptr;
2222708Swollman#endif /* defined ALL_STATE */
2232708Swollman
2242708Swollman#ifndef ALL_STATE
2252708Swollmanstatic struct state	lclmem;
2262708Swollmanstatic struct state	gmtmem;
2272708Swollman#define lclptr		(&lclmem)
2282708Swollman#define gmtptr		(&gmtmem)
2292708Swollman#endif /* State Farm */
2302708Swollman
2319936Swollman#ifndef TZ_STRLEN_MAX
2329936Swollman#define TZ_STRLEN_MAX 255
2339936Swollman#endif /* !defined TZ_STRLEN_MAX */
2349936Swollman
2359936Swollmanstatic char		lcl_TZname[TZ_STRLEN_MAX + 1];
2362708Swollmanstatic int		lcl_is_set;
2372708Swollmanstatic int		gmt_is_set;
238177824Sdavidxustatic pthread_rwlock_t	lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER;
23971579Sdeischenstatic pthread_mutex_t	gmt_mutex = PTHREAD_MUTEX_INITIALIZER;
2402708Swollman
2412708Swollmanchar *			tzname[2] = {
2429936Swollman	wildabbr,
2439936Swollman	wildabbr
2442708Swollman};
2452708Swollman
2469936Swollman/*
2479936Swollman** Section 4.12.3 of X3.159-1989 requires that
2489936Swollman**	Except for the strftime function, these functions [asctime,
2499936Swollman**	ctime, gmtime, localtime] return values in one of two static
2509936Swollman**	objects: a broken-down time structure and an array of char.
251192625Sedwin** Thanks to Paul Eggert for noting this.
2529936Swollman*/
2539936Swollman
2549936Swollmanstatic struct tm	tm;
2559936Swollman
2562708Swollman#ifdef USG_COMPAT
2572708Swollmantime_t			timezone = 0;
2582708Swollmanint			daylight = 0;
2592708Swollman#endif /* defined USG_COMPAT */
2602708Swollman
2612708Swollman#ifdef ALTZONE
2622708Swollmantime_t			altzone = 0;
2632708Swollman#endif /* defined ALTZONE */
2642708Swollman
2652708Swollmanstatic long
2662708Swollmandetzcode(codep)
2672708Swollmanconst char * const	codep;
2682708Swollman{
26992889Sobrien	long	result;
27092889Sobrien	int	i;
2712708Swollman
272192625Sedwin	result = (codep[0] & 0x80) ? ~0L : 0;
2732708Swollman	for (i = 0; i < 4; ++i)
2742708Swollman		result = (result << 8) | (codep[i] & 0xff);
2752708Swollman	return result;
2762708Swollman}
2772708Swollman
278192625Sedwinstatic time_t
279192625Sedwindetzcode64(codep)
280192625Sedwinconst char * const	codep;
281192625Sedwin{
282192625Sedwin	register time_t	result;
283192625Sedwin	register int	i;
284192625Sedwin
285192625Sedwin	result = (codep[0] & 0x80) ?  (~(int_fast64_t) 0) : 0;
286192625Sedwin	for (i = 0; i < 8; ++i)
287192625Sedwin		result = result * 256 + (codep[i] & 0xff);
288192625Sedwin	return result;
289192625Sedwin}
290192625Sedwin
2912708Swollmanstatic void
29297423Salfredsettzname(void)
2932708Swollman{
29492889Sobrien	struct state * 	sp = lclptr;
29592889Sobrien	int			i;
2962708Swollman
2979936Swollman	tzname[0] = wildabbr;
2989936Swollman	tzname[1] = wildabbr;
2992708Swollman#ifdef USG_COMPAT
3002708Swollman	daylight = 0;
3012708Swollman	timezone = 0;
3022708Swollman#endif /* defined USG_COMPAT */
3032708Swollman#ifdef ALTZONE
3042708Swollman	altzone = 0;
3052708Swollman#endif /* defined ALTZONE */
3062708Swollman#ifdef ALL_STATE
3072708Swollman	if (sp == NULL) {
3089936Swollman		tzname[0] = tzname[1] = gmt;
3092708Swollman		return;
3102708Swollman	}
3112708Swollman#endif /* defined ALL_STATE */
3122708Swollman	for (i = 0; i < sp->typecnt; ++i) {
31392889Sobrien		const struct ttinfo * const	ttisp = &sp->ttis[i];
3142708Swollman
3152708Swollman		tzname[ttisp->tt_isdst] =
3169936Swollman			&sp->chars[ttisp->tt_abbrind];
3172708Swollman#ifdef USG_COMPAT
3182708Swollman		if (ttisp->tt_isdst)
3192708Swollman			daylight = 1;
3202708Swollman		if (i == 0 || !ttisp->tt_isdst)
3212708Swollman			timezone = -(ttisp->tt_gmtoff);
3222708Swollman#endif /* defined USG_COMPAT */
3232708Swollman#ifdef ALTZONE
3242708Swollman		if (i == 0 || ttisp->tt_isdst)
3252708Swollman			altzone = -(ttisp->tt_gmtoff);
3262708Swollman#endif /* defined ALTZONE */
3272708Swollman	}
3282708Swollman	/*
3292708Swollman	** And to get the latest zone names into tzname. . .
3302708Swollman	*/
3312708Swollman	for (i = 0; i < sp->timecnt; ++i) {
33292889Sobrien		const struct ttinfo * const	ttisp =
3332708Swollman							&sp->ttis[
3342708Swollman								sp->types[i]];
3352708Swollman
3362708Swollman		tzname[ttisp->tt_isdst] =
3379936Swollman			&sp->chars[ttisp->tt_abbrind];
3382708Swollman	}
339192625Sedwin	/*
340192625Sedwin	** Finally, scrub the abbreviations.
341192625Sedwin	** First, replace bogus characters.
342192625Sedwin	*/
343192625Sedwin	for (i = 0; i < sp->charcnt; ++i)
344192625Sedwin		if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
345192625Sedwin			sp->chars[i] = TZ_ABBR_ERR_CHAR;
346192625Sedwin	/*
347192625Sedwin	** Second, truncate long abbreviations.
348192625Sedwin	*/
349192625Sedwin	for (i = 0; i < sp->typecnt; ++i) {
350192625Sedwin		register const struct ttinfo * const	ttisp = &sp->ttis[i];
351192625Sedwin		register char *				cp = &sp->chars[ttisp->tt_abbrind];
352192625Sedwin
353192625Sedwin		if (strlen(cp) > TZ_ABBR_MAX_LEN &&
354192625Sedwin			strcmp(cp, GRANDPARENTED) != 0)
355192625Sedwin				*(cp + TZ_ABBR_MAX_LEN) = '\0';
356192625Sedwin	}
3572708Swollman}
3582708Swollman
3592708Swollmanstatic int
360192625Sedwindiffer_by_repeat(t1, t0)
361192625Sedwinconst time_t	t1;
362192625Sedwinconst time_t	t0;
363192625Sedwin{
364192625Sedwin	int_fast64_t _t0 = t0;
365192625Sedwin	int_fast64_t _t1 = t1;
366192625Sedwin
367192625Sedwin	if (TYPE_INTEGRAL(time_t) &&
368192625Sedwin		TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
369192625Sedwin			return 0;
370192625Sedwin	//turn ((int_fast64_t)(t1 - t0) == SECSPERREPEAT);
371192625Sedwin	return _t1 - _t0 == SECSPERREPEAT;
372192625Sedwin}
373192625Sedwin
374192625Sedwinstatic int
375192625Sedwintzload(name, sp, doextend)
37692889Sobrienconst char *		name;
37792889Sobrienstruct state * const	sp;
378192625Sedwinregister const int	doextend;
3792708Swollman{
38092889Sobrien	const char *	p;
38192889Sobrien	int		i;
38292889Sobrien	int		fid;
383192625Sedwin	int		stored;
384192625Sedwin	int		nread;
385192625Sedwin	union {
386192625Sedwin		struct tzhead	tzhead;
387192625Sedwin		char		buf[2 * sizeof(struct tzhead) +
388192625Sedwin					2 * sizeof *sp +
389192625Sedwin					4 * TZ_MAX_TIMES];
390192625Sedwin	} u;
3912708Swollman
39239327Simp	/* XXX The following is from OpenBSD, and I'm not sure it is correct */
39339327Simp	if (name != NULL && issetugid() != 0)
39439327Simp		if ((name[0] == ':' && name[1] == '/') ||
39539327Simp		    name[0] == '/' || strchr(name, '.'))
39639327Simp			name = NULL;
3972708Swollman	if (name == NULL && (name = TZDEFAULT) == NULL)
3982708Swollman		return -1;
3992708Swollman	{
40092889Sobrien		int	doaccess;
40118834Swollman		struct stat	stab;
4029936Swollman		/*
4039936Swollman		** Section 4.9.1 of the C standard says that
4049936Swollman		** "FILENAME_MAX expands to an integral constant expression
40518834Swollman		** that is the size needed for an array of char large enough
4069936Swollman		** to hold the longest file name string that the implementation
4079936Swollman		** guarantees can be opened."
4089936Swollman		*/
4092708Swollman		char		fullname[FILENAME_MAX + 1];
4102708Swollman
4112708Swollman		if (name[0] == ':')
4122708Swollman			++name;
4132708Swollman		doaccess = name[0] == '/';
4142708Swollman		if (!doaccess) {
4152708Swollman			if ((p = TZDIR) == NULL)
4162708Swollman				return -1;
41739327Simp			if ((strlen(p) + 1 + strlen(name) + 1) >= sizeof fullname)
4182708Swollman				return -1;
4192708Swollman			(void) strcpy(fullname, p);
4202708Swollman			(void) strcat(fullname, "/");
4212708Swollman			(void) strcat(fullname, name);
4222708Swollman			/*
4232708Swollman			** Set doaccess if '.' (as in "../") shows up in name.
4242708Swollman			*/
4252708Swollman			if (strchr(name, '.') != NULL)
4262708Swollman				doaccess = TRUE;
4272708Swollman			name = fullname;
4282708Swollman		}
42924253Simp		if (doaccess && access(name, R_OK) != 0)
43039327Simp		     	return -1;
43156698Sjasone		if ((fid = _open(name, OPEN_MODE)) == -1)
4322708Swollman			return -1;
43395989Swollman		if ((_fstat(fid, &stab) < 0) || !S_ISREG(stab.st_mode)) {
43495989Swollman			_close(fid);
43518834Swollman			return -1;
43695989Swollman		}
4372708Swollman	}
438192625Sedwin	nread = _read(fid, u.buf, sizeof u.buf);
439192625Sedwin	if (_close(fid) < 0 || nread <= 0)
440192625Sedwin		return -1;
441192625Sedwin	for (stored = 4; stored <= 8; stored *= 2) {
4429936Swollman		int		ttisstdcnt;
4439936Swollman		int		ttisgmtcnt;
4442708Swollman
445130461Sstefanf		ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
446130461Sstefanf		ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
447130461Sstefanf		sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
448130461Sstefanf		sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
449130461Sstefanf		sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
450130461Sstefanf		sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
451130461Sstefanf		p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
4522708Swollman		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
4532708Swollman			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
4542708Swollman			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
4552708Swollman			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
4569936Swollman			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
4579936Swollman			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
4582708Swollman				return -1;
459192625Sedwin		if (nread - (p - u.buf) <
460192625Sedwin			sp->timecnt * stored +		/* ats */
4619936Swollman			sp->timecnt +			/* types */
462192625Sedwin			sp->typecnt * 6 +		/* ttinfos */
4639936Swollman			sp->charcnt +			/* chars */
464192625Sedwin			sp->leapcnt * (stored + 4) +	/* lsinfos */
4659936Swollman			ttisstdcnt +			/* ttisstds */
4669936Swollman			ttisgmtcnt)			/* ttisgmts */
4672708Swollman				return -1;
4682708Swollman		for (i = 0; i < sp->timecnt; ++i) {
469192625Sedwin			sp->ats[i] = (stored == 4) ?
470192625Sedwin				detzcode(p) : detzcode64(p);
471192625Sedwin			p += stored;
4722708Swollman		}
4732708Swollman		for (i = 0; i < sp->timecnt; ++i) {
4742708Swollman			sp->types[i] = (unsigned char) *p++;
4752708Swollman			if (sp->types[i] >= sp->typecnt)
4762708Swollman				return -1;
4772708Swollman		}
4782708Swollman		for (i = 0; i < sp->typecnt; ++i) {
47992889Sobrien			struct ttinfo *	ttisp;
4802708Swollman
4812708Swollman			ttisp = &sp->ttis[i];
4822708Swollman			ttisp->tt_gmtoff = detzcode(p);
4832708Swollman			p += 4;
4842708Swollman			ttisp->tt_isdst = (unsigned char) *p++;
4852708Swollman			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
4862708Swollman				return -1;
4872708Swollman			ttisp->tt_abbrind = (unsigned char) *p++;
4882708Swollman			if (ttisp->tt_abbrind < 0 ||
4892708Swollman				ttisp->tt_abbrind > sp->charcnt)
4902708Swollman					return -1;
4912708Swollman		}
4922708Swollman		for (i = 0; i < sp->charcnt; ++i)
4932708Swollman			sp->chars[i] = *p++;
4942708Swollman		sp->chars[i] = '\0';	/* ensure '\0' at end */
4952708Swollman		for (i = 0; i < sp->leapcnt; ++i) {
49692889Sobrien			struct lsinfo *	lsisp;
4972708Swollman
4982708Swollman			lsisp = &sp->lsis[i];
499192625Sedwin			lsisp->ls_trans = (stored == 4) ?
500192625Sedwin				detzcode(p) : detzcode64(p);
501192625Sedwin			p += stored;
5022708Swollman			lsisp->ls_corr = detzcode(p);
5032708Swollman			p += 4;
5042708Swollman		}
5052708Swollman		for (i = 0; i < sp->typecnt; ++i) {
50692889Sobrien			struct ttinfo *	ttisp;
5072708Swollman
5082708Swollman			ttisp = &sp->ttis[i];
5092708Swollman			if (ttisstdcnt == 0)
5102708Swollman				ttisp->tt_ttisstd = FALSE;
5112708Swollman			else {
5122708Swollman				ttisp->tt_ttisstd = *p++;
5132708Swollman				if (ttisp->tt_ttisstd != TRUE &&
5142708Swollman					ttisp->tt_ttisstd != FALSE)
5152708Swollman						return -1;
5162708Swollman			}
5172708Swollman		}
5189936Swollman		for (i = 0; i < sp->typecnt; ++i) {
51992889Sobrien			struct ttinfo *	ttisp;
5209936Swollman
5219936Swollman			ttisp = &sp->ttis[i];
5229936Swollman			if (ttisgmtcnt == 0)
5239936Swollman				ttisp->tt_ttisgmt = FALSE;
5249936Swollman			else {
5259936Swollman				ttisp->tt_ttisgmt = *p++;
5269936Swollman				if (ttisp->tt_ttisgmt != TRUE &&
5279936Swollman					ttisp->tt_ttisgmt != FALSE)
5289936Swollman						return -1;
5299936Swollman			}
5309936Swollman		}
531192625Sedwin		/*
532192625Sedwin		** Out-of-sort ats should mean we're running on a
533192625Sedwin		** signed time_t system but using a data file with
534192625Sedwin		** unsigned values (or vice versa).
535192625Sedwin		*/
536192625Sedwin		for (i = 0; i < sp->timecnt - 2; ++i)
537192625Sedwin			if (sp->ats[i] > sp->ats[i + 1]) {
538192625Sedwin				++i;
539192625Sedwin				if (TYPE_SIGNED(time_t)) {
540192625Sedwin					/*
541192625Sedwin					** Ignore the end (easy).
542192625Sedwin					*/
543192625Sedwin					sp->timecnt = i;
544192625Sedwin				} else {
545192625Sedwin					/*
546192625Sedwin					** Ignore the beginning (harder).
547192625Sedwin					*/
548192625Sedwin					register int	j;
549192625Sedwin
550192625Sedwin					for (j = 0; j + i < sp->timecnt; ++j) {
551192625Sedwin						sp->ats[j] = sp->ats[j + i];
552192625Sedwin						sp->types[j] = sp->types[j + i];
553192625Sedwin					}
554192625Sedwin					sp->timecnt = j;
555192625Sedwin				}
556192625Sedwin				break;
557192625Sedwin			}
558192625Sedwin		/*
559192625Sedwin		** If this is an old file, we're done.
560192625Sedwin		*/
561192625Sedwin		if (u.tzhead.tzh_version[0] == '\0')
562192625Sedwin			break;
563192625Sedwin		nread -= p - u.buf;
564192625Sedwin		for (i = 0; i < nread; ++i)
565192625Sedwin			u.buf[i] = p[i];
566192625Sedwin		/*
567192625Sedwin		** If this is a narrow integer time_t system, we're done.
568192625Sedwin		*/
569192625Sedwin		if (stored >= (int) sizeof(time_t) && TYPE_INTEGRAL(time_t))
570192625Sedwin			break;
5712708Swollman	}
572192625Sedwin	if (doextend && nread > 2 &&
573192625Sedwin		u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
574192625Sedwin		sp->typecnt + 2 <= TZ_MAX_TYPES) {
575192625Sedwin			struct state	ts;
576192625Sedwin			register int	result;
577192625Sedwin
578192625Sedwin			u.buf[nread - 1] = '\0';
579192625Sedwin			result = tzparse(&u.buf[1], &ts, FALSE);
580192625Sedwin			if (result == 0 && ts.typecnt == 2 &&
581192625Sedwin				sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
582192625Sedwin					for (i = 0; i < 2; ++i)
583192625Sedwin						ts.ttis[i].tt_abbrind +=
584192625Sedwin							sp->charcnt;
585192625Sedwin					for (i = 0; i < ts.charcnt; ++i)
586192625Sedwin						sp->chars[sp->charcnt++] =
587192625Sedwin							ts.chars[i];
588192625Sedwin					i = 0;
589192625Sedwin					while (i < ts.timecnt &&
590192625Sedwin						ts.ats[i] <=
591192625Sedwin						sp->ats[sp->timecnt - 1])
592192625Sedwin							++i;
593192625Sedwin					while (i < ts.timecnt &&
594192625Sedwin					    sp->timecnt < TZ_MAX_TIMES) {
595192625Sedwin						sp->ats[sp->timecnt] =
596192625Sedwin							ts.ats[i];
597192625Sedwin						sp->types[sp->timecnt] =
598192625Sedwin							sp->typecnt +
599192625Sedwin							ts.types[i];
600192625Sedwin						++sp->timecnt;
601192625Sedwin						++i;
602192625Sedwin					}
603192625Sedwin					sp->ttis[sp->typecnt++] = ts.ttis[0];
604192625Sedwin					sp->ttis[sp->typecnt++] = ts.ttis[1];
605192625Sedwin			}
606192625Sedwin	}
607192625Sedwin	sp->goback = sp->goahead = FALSE;
608192625Sedwin	if (sp->timecnt > 1) {
609192625Sedwin		for (i = 1; i < sp->timecnt; ++i)
610192625Sedwin			if (typesequiv(sp, sp->types[i], sp->types[0]) &&
611192625Sedwin				differ_by_repeat(sp->ats[i], sp->ats[0])) {
612192625Sedwin					sp->goback = TRUE;
613192625Sedwin					break;
614192625Sedwin				}
615192625Sedwin		for (i = sp->timecnt - 2; i >= 0; --i)
616192625Sedwin			if (typesequiv(sp, sp->types[sp->timecnt - 1],
617192625Sedwin				sp->types[i]) &&
618192625Sedwin				differ_by_repeat(sp->ats[sp->timecnt - 1],
619192625Sedwin				sp->ats[i])) {
620192625Sedwin					sp->goahead = TRUE;
621192625Sedwin					break;
622192625Sedwin		}
623192625Sedwin	}
6242708Swollman	return 0;
6252708Swollman}
6262708Swollman
627192625Sedwinstatic int
628192625Sedwintypesequiv(sp, a, b)
629192625Sedwinconst struct state * const	sp;
630192625Sedwinconst int			a;
631192625Sedwinconst int			b;
632192625Sedwin{
633192625Sedwin	register int	result;
634192625Sedwin
635192625Sedwin	if (sp == NULL ||
636192625Sedwin		a < 0 || a >= sp->typecnt ||
637192625Sedwin		b < 0 || b >= sp->typecnt)
638192625Sedwin			result = FALSE;
639192625Sedwin	else {
640192625Sedwin		register const struct ttinfo *	ap = &sp->ttis[a];
641192625Sedwin		register const struct ttinfo *	bp = &sp->ttis[b];
642192625Sedwin		result = ap->tt_gmtoff == bp->tt_gmtoff &&
643192625Sedwin			ap->tt_isdst == bp->tt_isdst &&
644192625Sedwin			ap->tt_ttisstd == bp->tt_ttisstd &&
645192625Sedwin			ap->tt_ttisgmt == bp->tt_ttisgmt &&
646192625Sedwin			strcmp(&sp->chars[ap->tt_abbrind],
647192625Sedwin			&sp->chars[bp->tt_abbrind]) == 0;
648192625Sedwin	}
649192625Sedwin	return result;
650192625Sedwin}
651192625Sedwin
6522708Swollmanstatic const int	mon_lengths[2][MONSPERYEAR] = {
6532708Swollman	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
6542708Swollman	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
6552708Swollman};
6562708Swollman
6572708Swollmanstatic const int	year_lengths[2] = {
6582708Swollman	DAYSPERNYEAR, DAYSPERLYEAR
6592708Swollman};
6602708Swollman
6612708Swollman/*
6622708Swollman** Given a pointer into a time zone string, scan until a character that is not
663192625Sedwin** a valid character in a zone name is found. Return a pointer to that
6642708Swollman** character.
6652708Swollman*/
6662708Swollman
6672708Swollmanstatic const char *
6682708Swollmangetzname(strp)
66992889Sobrienconst char *	strp;
6702708Swollman{
67192889Sobrien	char	c;
6722708Swollman
67317209Swollman	while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
6742708Swollman		c != '+')
6752708Swollman			++strp;
6762708Swollman	return strp;
6772708Swollman}
6782708Swollman
6792708Swollman/*
680192625Sedwin** Given a pointer into an extended time zone string, scan until the ending
681192625Sedwin** delimiter of the zone name is located. Return a pointer to the delimiter.
682192625Sedwin**
683192625Sedwin** As with getzname above, the legal character set is actually quite
684192625Sedwin** restricted, with other characters producing undefined results.
685192625Sedwin** We don't do any checking here; checking is done later in common-case code.
686192625Sedwin*/
687192625Sedwin
688192625Sedwinstatic const char *
689192625Sedwingetqzname(register const char *strp, const int delim)
690192625Sedwin{
691192625Sedwin	register int	c;
692192625Sedwin
693192625Sedwin	while ((c = *strp) != '\0' && c != delim)
694192625Sedwin		++strp;
695192625Sedwin	return strp;
696192625Sedwin}
697192625Sedwin
698192625Sedwin/*
6992708Swollman** Given a pointer into a time zone string, extract a number from that string.
7002708Swollman** Check that the number is within a specified range; if it is not, return
7012708Swollman** NULL.
7022708Swollman** Otherwise, return a pointer to the first character not part of the number.
7032708Swollman*/
7042708Swollman
7052708Swollmanstatic const char *
7062708Swollmangetnum(strp, nump, min, max)
70792889Sobrienconst char *	strp;
7082708Swollmanint * const		nump;
7092708Swollmanconst int		min;
7102708Swollmanconst int		max;
7112708Swollman{
71292889Sobrien	char	c;
71392889Sobrien	int	num;
7142708Swollman
71517209Swollman	if (strp == NULL || !is_digit(c = *strp))
7162708Swollman		return NULL;
7172708Swollman	num = 0;
71817209Swollman	do {
7192708Swollman		num = num * 10 + (c - '0');
7202708Swollman		if (num > max)
7212708Swollman			return NULL;	/* illegal value */
72217209Swollman		c = *++strp;
72317209Swollman	} while (is_digit(c));
7242708Swollman	if (num < min)
7252708Swollman		return NULL;		/* illegal value */
7262708Swollman	*nump = num;
7272708Swollman	return strp;
7282708Swollman}
7292708Swollman
7302708Swollman/*
7312708Swollman** Given a pointer into a time zone string, extract a number of seconds,
7322708Swollman** in hh[:mm[:ss]] form, from the string.
7332708Swollman** If any error occurs, return NULL.
7342708Swollman** Otherwise, return a pointer to the first character not part of the number
7352708Swollman** of seconds.
7362708Swollman*/
7372708Swollman
7382708Swollmanstatic const char *
7392708Swollmangetsecs(strp, secsp)
74092889Sobrienconst char *	strp;
7412708Swollmanlong * const		secsp;
7422708Swollman{
7432708Swollman	int	num;
7442708Swollman
7459936Swollman	/*
7469936Swollman	** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
7479936Swollman	** "M10.4.6/26", which does not conform to Posix,
7489936Swollman	** but which specifies the equivalent of
7499936Swollman	** ``02:00 on the first Sunday on or after 23 Oct''.
7509936Swollman	*/
7519936Swollman	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
7522708Swollman	if (strp == NULL)
7532708Swollman		return NULL;
7549936Swollman	*secsp = num * (long) SECSPERHOUR;
7552708Swollman	if (*strp == ':') {
7562708Swollman		++strp;
7572708Swollman		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
7582708Swollman		if (strp == NULL)
7592708Swollman			return NULL;
7602708Swollman		*secsp += num * SECSPERMIN;
7612708Swollman		if (*strp == ':') {
7622708Swollman			++strp;
763192625Sedwin			/* `SECSPERMIN' allows for leap seconds. */
7649936Swollman			strp = getnum(strp, &num, 0, SECSPERMIN);
7652708Swollman			if (strp == NULL)
7662708Swollman				return NULL;
7672708Swollman			*secsp += num;
7682708Swollman		}
7692708Swollman	}
7702708Swollman	return strp;
7712708Swollman}
7722708Swollman
7732708Swollman/*
7742708Swollman** Given a pointer into a time zone string, extract an offset, in
7752708Swollman** [+-]hh[:mm[:ss]] form, from the string.
7762708Swollman** If any error occurs, return NULL.
7772708Swollman** Otherwise, return a pointer to the first character not part of the time.
7782708Swollman*/
7792708Swollman
7802708Swollmanstatic const char *
7812708Swollmangetoffset(strp, offsetp)
78292889Sobrienconst char *	strp;
7832708Swollmanlong * const		offsetp;
7842708Swollman{
78592889Sobrien	int	neg = 0;
7862708Swollman
7872708Swollman	if (*strp == '-') {
7882708Swollman		neg = 1;
7892708Swollman		++strp;
79017209Swollman	} else if (*strp == '+')
79117209Swollman		++strp;
7922708Swollman	strp = getsecs(strp, offsetp);
7932708Swollman	if (strp == NULL)
7942708Swollman		return NULL;		/* illegal time */
7952708Swollman	if (neg)
7962708Swollman		*offsetp = -*offsetp;
7972708Swollman	return strp;
7982708Swollman}
7992708Swollman
8002708Swollman/*
8012708Swollman** Given a pointer into a time zone string, extract a rule in the form
802192625Sedwin** date[/time]. See POSIX section 8 for the format of "date" and "time".
8032708Swollman** If a valid rule is not found, return NULL.
8042708Swollman** Otherwise, return a pointer to the first character not part of the rule.
8052708Swollman*/
8062708Swollman
8072708Swollmanstatic const char *
8082708Swollmangetrule(strp, rulep)
8092708Swollmanconst char *			strp;
81092889Sobrienstruct rule * const	rulep;
8112708Swollman{
8122708Swollman	if (*strp == 'J') {
8132708Swollman		/*
8142708Swollman		** Julian day.
8152708Swollman		*/
8162708Swollman		rulep->r_type = JULIAN_DAY;
8172708Swollman		++strp;
8182708Swollman		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
8192708Swollman	} else if (*strp == 'M') {
8202708Swollman		/*
8212708Swollman		** Month, week, day.
8222708Swollman		*/
8232708Swollman		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
8242708Swollman		++strp;
8252708Swollman		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
8262708Swollman		if (strp == NULL)
8272708Swollman			return NULL;
8282708Swollman		if (*strp++ != '.')
8292708Swollman			return NULL;
8302708Swollman		strp = getnum(strp, &rulep->r_week, 1, 5);
8312708Swollman		if (strp == NULL)
8322708Swollman			return NULL;
8332708Swollman		if (*strp++ != '.')
8342708Swollman			return NULL;
8352708Swollman		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
83617209Swollman	} else if (is_digit(*strp)) {
8372708Swollman		/*
8382708Swollman		** Day of year.
8392708Swollman		*/
8402708Swollman		rulep->r_type = DAY_OF_YEAR;
8412708Swollman		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
8422708Swollman	} else	return NULL;		/* invalid format */
8432708Swollman	if (strp == NULL)
8442708Swollman		return NULL;
8452708Swollman	if (*strp == '/') {
8462708Swollman		/*
8472708Swollman		** Time specified.
8482708Swollman		*/
8492708Swollman		++strp;
8502708Swollman		strp = getsecs(strp, &rulep->r_time);
8512708Swollman	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
8522708Swollman	return strp;
8532708Swollman}
8542708Swollman
8552708Swollman/*
856130461Sstefanf** Given the Epoch-relative time of January 1, 00:00:00 UTC, in a year, the
857130461Sstefanf** year, a rule, and the offset from UTC at the time that rule takes effect,
8582708Swollman** calculate the Epoch-relative time that rule takes effect.
8592708Swollman*/
8602708Swollman
8612708Swollmanstatic time_t
8622708Swollmantranstime(janfirst, year, rulep, offset)
8632708Swollmanconst time_t				janfirst;
8642708Swollmanconst int				year;
86592889Sobrienconst struct rule * const	rulep;
8662708Swollmanconst long				offset;
8672708Swollman{
86892889Sobrien	int	leapyear;
86992889Sobrien	time_t	value;
87092889Sobrien	int	i;
8712708Swollman	int		d, m1, yy0, yy1, yy2, dow;
8722708Swollman
8739936Swollman	INITIALIZE(value);
8742708Swollman	leapyear = isleap(year);
8752708Swollman	switch (rulep->r_type) {
8762708Swollman
8772708Swollman	case JULIAN_DAY:
8782708Swollman		/*
8792708Swollman		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
8802708Swollman		** years.
8812708Swollman		** In non-leap years, or if the day number is 59 or less, just
8822708Swollman		** add SECSPERDAY times the day number-1 to the time of
8832708Swollman		** January 1, midnight, to get the day.
8842708Swollman		*/
8852708Swollman		value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
8862708Swollman		if (leapyear && rulep->r_day >= 60)
8872708Swollman			value += SECSPERDAY;
8882708Swollman		break;
8892708Swollman
8902708Swollman	case DAY_OF_YEAR:
8912708Swollman		/*
8922708Swollman		** n - day of year.
8932708Swollman		** Just add SECSPERDAY times the day number to the time of
8942708Swollman		** January 1, midnight, to get the day.
8952708Swollman		*/
8962708Swollman		value = janfirst + rulep->r_day * SECSPERDAY;
8972708Swollman		break;
8982708Swollman
8992708Swollman	case MONTH_NTH_DAY_OF_WEEK:
9002708Swollman		/*
9012708Swollman		** Mm.n.d - nth "dth day" of month m.
9022708Swollman		*/
9032708Swollman		value = janfirst;
9042708Swollman		for (i = 0; i < rulep->r_mon - 1; ++i)
9052708Swollman			value += mon_lengths[leapyear][i] * SECSPERDAY;
9062708Swollman
9072708Swollman		/*
9082708Swollman		** Use Zeller's Congruence to get day-of-week of first day of
9092708Swollman		** month.
9102708Swollman		*/
9112708Swollman		m1 = (rulep->r_mon + 9) % 12 + 1;
9122708Swollman		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
9132708Swollman		yy1 = yy0 / 100;
9142708Swollman		yy2 = yy0 % 100;
9152708Swollman		dow = ((26 * m1 - 2) / 10 +
9162708Swollman			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
9172708Swollman		if (dow < 0)
9182708Swollman			dow += DAYSPERWEEK;
9192708Swollman
9202708Swollman		/*
921192625Sedwin		** "dow" is the day-of-week of the first day of the month. Get
9222708Swollman		** the day-of-month (zero-origin) of the first "dow" day of the
9232708Swollman		** month.
9242708Swollman		*/
9252708Swollman		d = rulep->r_day - dow;
9262708Swollman		if (d < 0)
9272708Swollman			d += DAYSPERWEEK;
9282708Swollman		for (i = 1; i < rulep->r_week; ++i) {
9292708Swollman			if (d + DAYSPERWEEK >=
9302708Swollman				mon_lengths[leapyear][rulep->r_mon - 1])
9312708Swollman					break;
9322708Swollman			d += DAYSPERWEEK;
9332708Swollman		}
9342708Swollman
9352708Swollman		/*
9362708Swollman		** "d" is the day-of-month (zero-origin) of the day we want.
9372708Swollman		*/
9382708Swollman		value += d * SECSPERDAY;
9392708Swollman		break;
9402708Swollman	}
9412708Swollman
9422708Swollman	/*
943130461Sstefanf	** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
944192625Sedwin	** question. To get the Epoch-relative time of the specified local
9452708Swollman	** time on that day, add the transition time and the current offset
946130461Sstefanf	** from UTC.
9472708Swollman	*/
9482708Swollman	return value + rulep->r_time + offset;
9492708Swollman}
9502708Swollman
9512708Swollman/*
9522708Swollman** Given a POSIX section 8-style TZ string, fill in the rule tables as
9532708Swollman** appropriate.
9542708Swollman*/
9552708Swollman
9562708Swollmanstatic int
9572708Swollmantzparse(name, sp, lastditch)
9582708Swollmanconst char *			name;
95992889Sobrienstruct state * const	sp;
9602708Swollmanconst int			lastditch;
9612708Swollman{
9622708Swollman	const char *			stdname;
9632708Swollman	const char *			dstname;
9649936Swollman	size_t				stdlen;
9659936Swollman	size_t				dstlen;
9662708Swollman	long				stdoffset;
9672708Swollman	long				dstoffset;
96892889Sobrien	time_t *		atp;
96992889Sobrien	unsigned char *	typep;
97092889Sobrien	char *			cp;
97192889Sobrien	int			load_result;
9722708Swollman
9739936Swollman	INITIALIZE(dstname);
9742708Swollman	stdname = name;
9752708Swollman	if (lastditch) {
9762708Swollman		stdlen = strlen(name);	/* length of standard zone name */
9772708Swollman		name += stdlen;
9782708Swollman		if (stdlen >= sizeof sp->chars)
9792708Swollman			stdlen = (sizeof sp->chars) - 1;
98021659Swollman		stdoffset = 0;
9812708Swollman	} else {
982192625Sedwin		if (*name == '<') {
983192625Sedwin			name++;
984192625Sedwin			stdname = name;
985192625Sedwin			name = getqzname(name, '>');
986192625Sedwin			if (*name != '>')
987192625Sedwin				return (-1);
988192625Sedwin			stdlen = name - stdname;
989192625Sedwin			name++;
990192625Sedwin		} else {
991192625Sedwin			name = getzname(name);
992192625Sedwin			stdlen = name - stdname;
993192625Sedwin		}
99421659Swollman		if (*name == '\0')
99521659Swollman			return -1;	/* was "stdoffset = 0;" */
99621659Swollman		else {
99721659Swollman			name = getoffset(name, &stdoffset);
99821659Swollman			if (name == NULL)
99921659Swollman				return -1;
100021659Swollman		}
10012708Swollman	}
1002192625Sedwin	load_result = tzload(TZDEFRULES, sp, FALSE);
10032708Swollman	if (load_result != 0)
10042708Swollman		sp->leapcnt = 0;		/* so, we're off a little */
10052708Swollman	if (*name != '\0') {
1006192625Sedwin		if (*name == '<') {
1007192625Sedwin			dstname = ++name;
1008192625Sedwin			name = getqzname(name, '>');
1009192625Sedwin			if (*name != '>')
1010192625Sedwin				return -1;
1011192625Sedwin			dstlen = name - dstname;
1012192625Sedwin			name++;
1013192625Sedwin		} else {
1014192625Sedwin			dstname = name;
1015192625Sedwin			name = getzname(name);
1016192625Sedwin			dstlen = name - dstname; /* length of DST zone name */
1017192625Sedwin		}
10182708Swollman		if (*name != '\0' && *name != ',' && *name != ';') {
10192708Swollman			name = getoffset(name, &dstoffset);
10202708Swollman			if (name == NULL)
10212708Swollman				return -1;
10222708Swollman		} else	dstoffset = stdoffset - SECSPERHOUR;
1023130461Sstefanf		if (*name == '\0' && load_result != 0)
1024130461Sstefanf			name = TZDEFRULESTRING;
10252708Swollman		if (*name == ',' || *name == ';') {
10262708Swollman			struct rule	start;
10272708Swollman			struct rule	end;
102892889Sobrien			int	year;
102992889Sobrien			time_t	janfirst;
10302708Swollman			time_t		starttime;
10312708Swollman			time_t		endtime;
10322708Swollman
10332708Swollman			++name;
10342708Swollman			if ((name = getrule(name, &start)) == NULL)
10352708Swollman				return -1;
10362708Swollman			if (*name++ != ',')
10372708Swollman				return -1;
10382708Swollman			if ((name = getrule(name, &end)) == NULL)
10392708Swollman				return -1;
10402708Swollman			if (*name != '\0')
10412708Swollman				return -1;
10422708Swollman			sp->typecnt = 2;	/* standard time and DST */
10432708Swollman			/*
1044192625Sedwin			** Two transitions per year, from EPOCH_YEAR forward.
10452708Swollman			*/
10462708Swollman			sp->ttis[0].tt_gmtoff = -dstoffset;
10472708Swollman			sp->ttis[0].tt_isdst = 1;
10482708Swollman			sp->ttis[0].tt_abbrind = stdlen + 1;
10492708Swollman			sp->ttis[1].tt_gmtoff = -stdoffset;
10502708Swollman			sp->ttis[1].tt_isdst = 0;
10512708Swollman			sp->ttis[1].tt_abbrind = 0;
10522708Swollman			atp = sp->ats;
10532708Swollman			typep = sp->types;
10542708Swollman			janfirst = 0;
1055192625Sedwin			sp->timecnt = 0;
1056192625Sedwin			for (year = EPOCH_YEAR;
1057192625Sedwin			    sp->timecnt + 2 <= TZ_MAX_TIMES;
1058192625Sedwin			    ++year) {
1059192625Sedwin			    	time_t	newfirst;
1060192625Sedwin
10612708Swollman				starttime = transtime(janfirst, year, &start,
10622708Swollman					stdoffset);
10632708Swollman				endtime = transtime(janfirst, year, &end,
10642708Swollman					dstoffset);
10652708Swollman				if (starttime > endtime) {
10662708Swollman					*atp++ = endtime;
10672708Swollman					*typep++ = 1;	/* DST ends */
10682708Swollman					*atp++ = starttime;
10692708Swollman					*typep++ = 0;	/* DST begins */
10702708Swollman				} else {
10712708Swollman					*atp++ = starttime;
10722708Swollman					*typep++ = 0;	/* DST begins */
10732708Swollman					*atp++ = endtime;
10742708Swollman					*typep++ = 1;	/* DST ends */
10752708Swollman				}
1076192625Sedwin				sp->timecnt += 2;
1077192625Sedwin				newfirst = janfirst;
1078192625Sedwin				newfirst += year_lengths[isleap(year)] *
10792708Swollman					SECSPERDAY;
1080192625Sedwin				if (newfirst <= janfirst)
1081192625Sedwin					break;
1082192625Sedwin				janfirst = newfirst;
10832708Swollman			}
10842708Swollman		} else {
108592889Sobrien			long	theirstdoffset;
108692889Sobrien			long	theirdstoffset;
108792889Sobrien			long	theiroffset;
108892889Sobrien			int	isdst;
108992889Sobrien			int	i;
109092889Sobrien			int	j;
10912708Swollman
10922708Swollman			if (*name != '\0')
10932708Swollman				return -1;
10942708Swollman			/*
10959936Swollman			** Initial values of theirstdoffset and theirdstoffset.
10962708Swollman			*/
10979936Swollman			theirstdoffset = 0;
10989936Swollman			for (i = 0; i < sp->timecnt; ++i) {
10999936Swollman				j = sp->types[i];
11009936Swollman				if (!sp->ttis[j].tt_isdst) {
110117209Swollman					theirstdoffset =
110217209Swollman						-sp->ttis[j].tt_gmtoff;
11039936Swollman					break;
11042708Swollman				}
11052708Swollman			}
11069936Swollman			theirdstoffset = 0;
11079936Swollman			for (i = 0; i < sp->timecnt; ++i) {
11089936Swollman				j = sp->types[i];
11099936Swollman				if (sp->ttis[j].tt_isdst) {
111017209Swollman					theirdstoffset =
111117209Swollman						-sp->ttis[j].tt_gmtoff;
11129936Swollman					break;
11139936Swollman				}
11149936Swollman			}
11152708Swollman			/*
11169936Swollman			** Initially we're assumed to be in standard time.
11172708Swollman			*/
11189936Swollman			isdst = FALSE;
11199936Swollman			theiroffset = theirstdoffset;
11202708Swollman			/*
11219936Swollman			** Now juggle transition times and types
11229936Swollman			** tracking offsets as you do.
11232708Swollman			*/
11242708Swollman			for (i = 0; i < sp->timecnt; ++i) {
11259936Swollman				j = sp->types[i];
11269936Swollman				sp->types[i] = sp->ttis[j].tt_isdst;
11279936Swollman				if (sp->ttis[j].tt_ttisgmt) {
11289936Swollman					/* No adjustment to transition time */
11299936Swollman				} else {
11309936Swollman					/*
11319936Swollman					** If summer time is in effect, and the
11329936Swollman					** transition time was not specified as
11339936Swollman					** standard time, add the summer time
11349936Swollman					** offset to the transition time;
11359936Swollman					** otherwise, add the standard time
11369936Swollman					** offset to the transition time.
11379936Swollman					*/
11389936Swollman					/*
11399936Swollman					** Transitions from DST to DDST
11409936Swollman					** will effectively disappear since
11419936Swollman					** POSIX provides for only one DST
11429936Swollman					** offset.
11439936Swollman					*/
11449936Swollman					if (isdst && !sp->ttis[j].tt_ttisstd) {
11459936Swollman						sp->ats[i] += dstoffset -
11469936Swollman							theirdstoffset;
11479936Swollman					} else {
11489936Swollman						sp->ats[i] += stdoffset -
11499936Swollman							theirstdoffset;
11509936Swollman					}
11519936Swollman				}
11529936Swollman				theiroffset = -sp->ttis[j].tt_gmtoff;
11539936Swollman				if (sp->ttis[j].tt_isdst)
11549936Swollman					theirdstoffset = theiroffset;
11559936Swollman				else	theirstdoffset = theiroffset;
11562708Swollman			}
11579936Swollman			/*
11589936Swollman			** Finally, fill in ttis.
11599936Swollman			** ttisstd and ttisgmt need not be handled.
11609936Swollman			*/
11619936Swollman			sp->ttis[0].tt_gmtoff = -stdoffset;
11629936Swollman			sp->ttis[0].tt_isdst = FALSE;
11639936Swollman			sp->ttis[0].tt_abbrind = 0;
11649936Swollman			sp->ttis[1].tt_gmtoff = -dstoffset;
11659936Swollman			sp->ttis[1].tt_isdst = TRUE;
11669936Swollman			sp->ttis[1].tt_abbrind = stdlen + 1;
1167130461Sstefanf			sp->typecnt = 2;
11682708Swollman		}
11692708Swollman	} else {
11702708Swollman		dstlen = 0;
11712708Swollman		sp->typecnt = 1;		/* only standard time */
11722708Swollman		sp->timecnt = 0;
11732708Swollman		sp->ttis[0].tt_gmtoff = -stdoffset;
11742708Swollman		sp->ttis[0].tt_isdst = 0;
11752708Swollman		sp->ttis[0].tt_abbrind = 0;
11762708Swollman	}
11772708Swollman	sp->charcnt = stdlen + 1;
11782708Swollman	if (dstlen != 0)
11792708Swollman		sp->charcnt += dstlen + 1;
1180130461Sstefanf	if ((size_t) sp->charcnt > sizeof sp->chars)
11812708Swollman		return -1;
11822708Swollman	cp = sp->chars;
11832708Swollman	(void) strncpy(cp, stdname, stdlen);
11842708Swollman	cp += stdlen;
11852708Swollman	*cp++ = '\0';
11862708Swollman	if (dstlen != 0) {
11872708Swollman		(void) strncpy(cp, dstname, dstlen);
11882708Swollman		*(cp + dstlen) = '\0';
11892708Swollman	}
11902708Swollman	return 0;
11912708Swollman}
11922708Swollman
11932708Swollmanstatic void
11942708Swollmangmtload(sp)
11952708Swollmanstruct state * const	sp;
11962708Swollman{
1197192625Sedwin	if (tzload(gmt, sp, TRUE) != 0)
11989936Swollman		(void) tzparse(gmt, sp, TRUE);
11992708Swollman}
12002708Swollman
120171579Sdeischenstatic void
1202177824Sdavidxutzsetwall_basic(int rdlocked)
12032708Swollman{
1204177824Sdavidxu	if (!rdlocked)
1205177824Sdavidxu		_RWLOCK_RDLOCK(&lcl_rwlock);
1206177824Sdavidxu	if (lcl_is_set < 0) {
1207177824Sdavidxu		if (!rdlocked)
1208177824Sdavidxu			_RWLOCK_UNLOCK(&lcl_rwlock);
12099936Swollman		return;
1210177824Sdavidxu	}
1211177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
1212177824Sdavidxu
1213177824Sdavidxu	_RWLOCK_WRLOCK(&lcl_rwlock);
12149936Swollman	lcl_is_set = -1;
12159936Swollman
12162708Swollman#ifdef ALL_STATE
12172708Swollman	if (lclptr == NULL) {
12182708Swollman		lclptr = (struct state *) malloc(sizeof *lclptr);
12192708Swollman		if (lclptr == NULL) {
12202708Swollman			settzname();	/* all we can do */
1221177824Sdavidxu			_RWLOCK_UNLOCK(&lcl_rwlock);
1222177824Sdavidxu			if (rdlocked)
1223177824Sdavidxu				_RWLOCK_RDLOCK(&lcl_rwlock);
12242708Swollman			return;
12252708Swollman		}
12262708Swollman	}
12272708Swollman#endif /* defined ALL_STATE */
1228192625Sedwin	if (tzload((char *) NULL, lclptr, TRUE) != 0)
12292708Swollman		gmtload(lclptr);
12302708Swollman	settzname();
1231177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
1232177824Sdavidxu
1233177824Sdavidxu	if (rdlocked)
1234177824Sdavidxu		_RWLOCK_RDLOCK(&lcl_rwlock);
12352708Swollman}
12362708Swollman
12372708Swollmanvoid
123897423Salfredtzsetwall(void)
123913545Sjulian{
1240177824Sdavidxu	tzsetwall_basic(0);
124113545Sjulian}
124213545Sjulian
124313545Sjulianstatic void
1244177824Sdavidxutzset_basic(int rdlocked)
12452708Swollman{
124692889Sobrien	const char *	name;
12472708Swollman
12482708Swollman	name = getenv("TZ");
12492708Swollman	if (name == NULL) {
1250177824Sdavidxu		tzsetwall_basic(rdlocked);
12512708Swollman		return;
12522708Swollman	}
12539936Swollman
1254177824Sdavidxu	if (!rdlocked)
1255177824Sdavidxu		_RWLOCK_RDLOCK(&lcl_rwlock);
1256177824Sdavidxu	if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) {
1257177824Sdavidxu		if (!rdlocked)
1258177824Sdavidxu			_RWLOCK_UNLOCK(&lcl_rwlock);
12599936Swollman		return;
1260177824Sdavidxu	}
1261177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
1262177824Sdavidxu
1263177824Sdavidxu	_RWLOCK_WRLOCK(&lcl_rwlock);
1264130461Sstefanf	lcl_is_set = strlen(name) < sizeof lcl_TZname;
12659936Swollman	if (lcl_is_set)
12669936Swollman		(void) strcpy(lcl_TZname, name);
12679936Swollman
12682708Swollman#ifdef ALL_STATE
12692708Swollman	if (lclptr == NULL) {
12702708Swollman		lclptr = (struct state *) malloc(sizeof *lclptr);
12712708Swollman		if (lclptr == NULL) {
12722708Swollman			settzname();	/* all we can do */
1273177824Sdavidxu			_RWLOCK_UNLOCK(&lcl_rwlock);
1274177824Sdavidxu			if (rdlocked)
1275177824Sdavidxu				_RWLOCK_RDLOCK(&lcl_rwlock);
12762708Swollman			return;
12772708Swollman		}
12782708Swollman	}
12792708Swollman#endif /* defined ALL_STATE */
12802708Swollman	if (*name == '\0') {
12812708Swollman		/*
12822708Swollman		** User wants it fast rather than right.
12832708Swollman		*/
12842708Swollman		lclptr->leapcnt = 0;		/* so, we're off a little */
12852708Swollman		lclptr->timecnt = 0;
1286130461Sstefanf		lclptr->typecnt = 0;
1287130461Sstefanf		lclptr->ttis[0].tt_isdst = 0;
12882708Swollman		lclptr->ttis[0].tt_gmtoff = 0;
12892708Swollman		lclptr->ttis[0].tt_abbrind = 0;
12909936Swollman		(void) strcpy(lclptr->chars, gmt);
1291192625Sedwin	} else if (tzload(name, lclptr, TRUE) != 0)
12922708Swollman		if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
12932708Swollman			(void) gmtload(lclptr);
12942708Swollman	settzname();
1295177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
1296177824Sdavidxu
1297177824Sdavidxu	if (rdlocked)
1298177824Sdavidxu		_RWLOCK_RDLOCK(&lcl_rwlock);
12992708Swollman}
13002708Swollman
130113545Sjulianvoid
130297423Salfredtzset(void)
130313545Sjulian{
1304177824Sdavidxu	tzset_basic(0);
130513545Sjulian}
130613545Sjulian
13072708Swollman/*
13082708Swollman** The easy way to behave "as if no library function calls" localtime
13092708Swollman** is to not call it--so we drop its guts into "localsub", which can be
1310192625Sedwin** freely called. (And no, the PANS doesn't require the above behavior--
13112708Swollman** but it *is* desirable.)
13122708Swollman**
13132708Swollman** The unused offset argument is for the benefit of mktime variants.
13142708Swollman*/
13152708Swollman
13162708Swollman/*ARGSUSED*/
1317192625Sedwinstatic struct tm *
13182708Swollmanlocalsub(timep, offset, tmp)
13192708Swollmanconst time_t * const	timep;
13202708Swollmanconst long		offset;
13212708Swollmanstruct tm * const	tmp;
13222708Swollman{
132392889Sobrien	struct state *		sp;
132492889Sobrien	const struct ttinfo *	ttisp;
132592889Sobrien	int			i;
1326192625Sedwin	struct tm *		result;
1327192625Sedwin	const time_t		t = *timep;
13282708Swollman
13292708Swollman	sp = lclptr;
13302708Swollman#ifdef ALL_STATE
1331192625Sedwin	if (sp == NULL)
1332192625Sedwin		return gmtsub(timep, offset, tmp);
1333192625Sedwin#endif /* defined ALL_STATE */
1334192625Sedwin	if ((sp->goback && t < sp->ats[0]) ||
1335192625Sedwin		(sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1336192625Sedwin			time_t			newt = t;
1337192625Sedwin			register time_t		seconds;
1338192625Sedwin			register time_t		tcycles;
1339192625Sedwin			register int_fast64_t	icycles;
1340192625Sedwin
1341192625Sedwin			if (t < sp->ats[0])
1342192625Sedwin				seconds = sp->ats[0] - t;
1343192625Sedwin			else	seconds = t - sp->ats[sp->timecnt - 1];
1344192625Sedwin			--seconds;
1345192625Sedwin			tcycles = seconds / YEARSPERREPEAT / AVGSECSPERYEAR;
1346192625Sedwin			++tcycles;
1347192625Sedwin			icycles = tcycles;
1348192625Sedwin			if (tcycles - icycles >= 1 || icycles - tcycles >= 1)
1349192625Sedwin				return NULL;
1350192625Sedwin			seconds = icycles;
1351192625Sedwin			seconds *= YEARSPERREPEAT;
1352192625Sedwin			seconds *= AVGSECSPERYEAR;
1353192625Sedwin			if (t < sp->ats[0])
1354192625Sedwin				newt += seconds;
1355192625Sedwin			else	newt -= seconds;
1356192625Sedwin			if (newt < sp->ats[0] ||
1357192625Sedwin				newt > sp->ats[sp->timecnt - 1])
1358192625Sedwin					return NULL;	/* "cannot happen" */
1359192625Sedwin			result = localsub(&newt, offset, tmp);
1360192625Sedwin			if (result == tmp) {
1361192625Sedwin				register time_t	newy;
1362192625Sedwin
1363192625Sedwin				newy = tmp->tm_year;
1364192625Sedwin				if (t < sp->ats[0])
1365192625Sedwin					newy -= icycles * YEARSPERREPEAT;
1366192625Sedwin				else	newy += icycles * YEARSPERREPEAT;
1367192625Sedwin				tmp->tm_year = newy;
1368192625Sedwin				if (tmp->tm_year != newy)
1369192625Sedwin					return NULL;
1370192625Sedwin			}
1371192625Sedwin			return result;
13722708Swollman	}
13732708Swollman	if (sp->timecnt == 0 || t < sp->ats[0]) {
13742708Swollman		i = 0;
13752708Swollman		while (sp->ttis[i].tt_isdst)
13762708Swollman			if (++i >= sp->typecnt) {
13772708Swollman				i = 0;
13782708Swollman				break;
13792708Swollman			}
13802708Swollman	} else {
1381192625Sedwin		register int	lo = 1;
1382192625Sedwin		register int	hi = sp->timecnt;
1383192625Sedwin
1384192625Sedwin		while (lo < hi) {
1385192625Sedwin			register int	mid = (lo + hi) >> 1;
1386192625Sedwin
1387192625Sedwin			if (t < sp->ats[mid])
1388192625Sedwin				hi = mid;
1389192625Sedwin			else	lo = mid + 1;
1390192625Sedwin		}
1391192625Sedwin		i = (int) sp->types[lo - 1];
13922708Swollman	}
13932708Swollman	ttisp = &sp->ttis[i];
13942708Swollman	/*
13952708Swollman	** To get (wrong) behavior that's compatible with System V Release 2.0
13962708Swollman	** you'd replace the statement below with
13972708Swollman	**	t += ttisp->tt_gmtoff;
13982708Swollman	**	timesub(&t, 0L, sp, tmp);
13992708Swollman	*/
1400192625Sedwin	result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
14012708Swollman	tmp->tm_isdst = ttisp->tt_isdst;
14029936Swollman	tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
14032708Swollman#ifdef TM_ZONE
14049936Swollman	tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
14052708Swollman#endif /* defined TM_ZONE */
1406192625Sedwin	return result;
14072708Swollman}
14082708Swollman
140919636Shsustruct tm *
14102708Swollmanlocaltime(timep)
14112708Swollmanconst time_t * const	timep;
14122708Swollman{
141371579Sdeischen	static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
141413545Sjulian	static pthread_key_t localtime_key = -1;
141513545Sjulian	struct tm *p_tm;
141613545Sjulian
141771579Sdeischen	if (__isthreaded != 0) {
141871579Sdeischen		if (localtime_key < 0) {
1419174766Simp			_pthread_mutex_lock(&localtime_mutex);
1420174766Simp			if (localtime_key < 0) {
1421174766Simp				if (_pthread_key_create(&localtime_key, free) < 0) {
1422174766Simp					_pthread_mutex_unlock(&localtime_mutex);
1423174766Simp					return(NULL);
1424174766Simp				}
142571579Sdeischen			}
1426174766Simp			_pthread_mutex_unlock(&localtime_mutex);
142713545Sjulian		}
142871579Sdeischen		p_tm = _pthread_getspecific(localtime_key);
142971579Sdeischen		if (p_tm == NULL) {
143071579Sdeischen			if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
143171579Sdeischen			    == NULL)
143271579Sdeischen				return(NULL);
143371579Sdeischen			_pthread_setspecific(localtime_key, p_tm);
143471579Sdeischen		}
1435177824Sdavidxu		_RWLOCK_RDLOCK(&lcl_rwlock);
1436177824Sdavidxu		tzset_basic(1);
143771579Sdeischen		localsub(timep, 0L, p_tm);
1438177824Sdavidxu		_RWLOCK_UNLOCK(&lcl_rwlock);
143971579Sdeischen		return(p_tm);
144071579Sdeischen	} else {
1441177824Sdavidxu		tzset_basic(0);
144271579Sdeischen		localsub(timep, 0L, &tm);
144371579Sdeischen		return(&tm);
144413545Sjulian	}
14452708Swollman}
14462708Swollman
14472708Swollman/*
1448130461Sstefanf** Re-entrant version of localtime.
1449130461Sstefanf*/
1450130461Sstefanf
1451130461Sstefanfstruct tm *
1452192625Sedwinlocaltime_r(timep, tmp)
1453130461Sstefanfconst time_t * const	timep;
1454192625Sedwinstruct tm *		tmp;
1455130461Sstefanf{
1456177824Sdavidxu	_RWLOCK_RDLOCK(&lcl_rwlock);
1457177824Sdavidxu	tzset_basic(1);
1458192625Sedwin	localsub(timep, 0L, tmp);
1459177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
1460192625Sedwin	return tmp;
1461130461Sstefanf}
1462130461Sstefanf
1463130461Sstefanf/*
14642708Swollman** gmtsub is to gmtime as localsub is to localtime.
14652708Swollman*/
14662708Swollman
1467192625Sedwinstatic struct tm *
14682708Swollmangmtsub(timep, offset, tmp)
14692708Swollmanconst time_t * const	timep;
14702708Swollmanconst long		offset;
14712708Swollmanstruct tm * const	tmp;
14722708Swollman{
1473192625Sedwin	register struct tm *	result;
1474192625Sedwin
14752708Swollman	if (!gmt_is_set) {
1476174766Simp		_MUTEX_LOCK(&gmt_mutex);
1477174766Simp		if (!gmt_is_set) {
14782708Swollman#ifdef ALL_STATE
1479174766Simp			gmtptr = (struct state *) malloc(sizeof *gmtptr);
1480174766Simp			if (gmtptr != NULL)
14812708Swollman#endif /* defined ALL_STATE */
1482174766Simp				gmtload(gmtptr);
1483174766Simp			gmt_is_set = TRUE;
1484174766Simp		}
1485174766Simp		_MUTEX_UNLOCK(&gmt_mutex);
14862708Swollman	}
1487192625Sedwin	result = timesub(timep, offset, gmtptr, tmp);
14882708Swollman#ifdef TM_ZONE
14892708Swollman	/*
14902708Swollman	** Could get fancy here and deliver something such as
1491130461Sstefanf	** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
14922708Swollman	** but this is no time for a treasure hunt.
14932708Swollman	*/
14942708Swollman	if (offset != 0)
14959936Swollman		tmp->TM_ZONE = wildabbr;
14962708Swollman	else {
14972708Swollman#ifdef ALL_STATE
14982708Swollman		if (gmtptr == NULL)
14999936Swollman			tmp->TM_ZONE = gmt;
15002708Swollman		else	tmp->TM_ZONE = gmtptr->chars;
15012708Swollman#endif /* defined ALL_STATE */
15022708Swollman#ifndef ALL_STATE
15032708Swollman		tmp->TM_ZONE = gmtptr->chars;
15042708Swollman#endif /* State Farm */
15052708Swollman	}
15062708Swollman#endif /* defined TM_ZONE */
1507192625Sedwin	return result;
15082708Swollman}
15092708Swollman
15102708Swollmanstruct tm *
15112708Swollmangmtime(timep)
15122708Swollmanconst time_t * const	timep;
15132708Swollman{
151471579Sdeischen	static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
151513545Sjulian	static pthread_key_t gmtime_key = -1;
151613545Sjulian	struct tm *p_tm;
151713545Sjulian
151871579Sdeischen	if (__isthreaded != 0) {
151971579Sdeischen		if (gmtime_key < 0) {
1520174766Simp			_pthread_mutex_lock(&gmtime_mutex);
1521174766Simp			if (gmtime_key < 0) {
1522174766Simp				if (_pthread_key_create(&gmtime_key, free) < 0) {
1523174766Simp					_pthread_mutex_unlock(&gmtime_mutex);
1524174766Simp					return(NULL);
1525174766Simp				}
152671579Sdeischen			}
1527174766Simp			_pthread_mutex_unlock(&gmtime_mutex);
152813545Sjulian		}
152971579Sdeischen		/*
153071579Sdeischen		 * Changed to follow POSIX.1 threads standard, which
153171579Sdeischen		 * is what BSD currently has.
153271579Sdeischen		 */
153371579Sdeischen		if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) {
153471579Sdeischen			if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
153571579Sdeischen			    == NULL) {
153671579Sdeischen				return(NULL);
153771579Sdeischen			}
153871579Sdeischen			_pthread_setspecific(gmtime_key, p_tm);
153913545Sjulian		}
154071579Sdeischen		gmtsub(timep, 0L, p_tm);
154171579Sdeischen		return(p_tm);
154213545Sjulian	}
154371579Sdeischen	else {
154471579Sdeischen		gmtsub(timep, 0L, &tm);
154571579Sdeischen		return(&tm);
154671579Sdeischen	}
15472708Swollman}
15482708Swollman
1549130461Sstefanf/*
1550130461Sstefanf* Re-entrant version of gmtime.
1551130461Sstefanf*/
1552130461Sstefanf
155319636Shsustruct tm *
1554192625Sedwingmtime_r(timep, tmp)
1555130461Sstefanfconst time_t * const	timep;
1556192625Sedwinstruct tm *		tmp;
155713545Sjulian{
1558192625Sedwin	return gmtsub(timep, 0L, tmp);
155913545Sjulian}
156013545Sjulian
15612708Swollman#ifdef STD_INSPIRED
15622708Swollman
15632708Swollmanstruct tm *
15642708Swollmanofftime(timep, offset)
15652708Swollmanconst time_t * const	timep;
15662708Swollmanconst long		offset;
15672708Swollman{
1568192625Sedwin	return gmtsub(timep, offset, &tm);
15692708Swollman}
15702708Swollman
15712708Swollman#endif /* defined STD_INSPIRED */
15722708Swollman
1573192625Sedwin/*
1574192625Sedwin** Return the number of leap years through the end of the given year
1575192625Sedwin** where, to make the math easy, the answer for year zero is defined as zero.
1576192625Sedwin*/
1577192625Sedwin
1578192625Sedwinstatic int
1579192625Sedwinleaps_thru_end_of(y)
1580192625Sedwinregister const int	y;
1581192625Sedwin{
1582192625Sedwin	return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1583192625Sedwin		-(leaps_thru_end_of(-(y + 1)) + 1);
1584192625Sedwin}
1585192625Sedwin
1586192625Sedwinstatic struct tm *
15872708Swollmantimesub(timep, offset, sp, tmp)
15882708Swollmanconst time_t * const			timep;
15892708Swollmanconst long				offset;
159092889Sobrienconst struct state * const	sp;
159192889Sobrienstruct tm * const		tmp;
15922708Swollman{
159392889Sobrien	const struct lsinfo *	lp;
1594192625Sedwin	time_t			tdays;
1595192625Sedwin	int			idays;	/* unsigned would be so 2003 */
159692889Sobrien	long			rem;
1597192625Sedwin	int			y;
159892889Sobrien	const int *		ip;
159992889Sobrien	long			corr;
160092889Sobrien	int			hit;
160192889Sobrien	int			i;
16022708Swollman
16032708Swollman	corr = 0;
16042708Swollman	hit = 0;
16052708Swollman#ifdef ALL_STATE
16062708Swollman	i = (sp == NULL) ? 0 : sp->leapcnt;
16072708Swollman#endif /* defined ALL_STATE */
16082708Swollman#ifndef ALL_STATE
16092708Swollman	i = sp->leapcnt;
16102708Swollman#endif /* State Farm */
16112708Swollman	while (--i >= 0) {
16122708Swollman		lp = &sp->lsis[i];
16132708Swollman		if (*timep >= lp->ls_trans) {
16142708Swollman			if (*timep == lp->ls_trans) {
16152708Swollman				hit = ((i == 0 && lp->ls_corr > 0) ||
16162708Swollman					lp->ls_corr > sp->lsis[i - 1].ls_corr);
16172708Swollman				if (hit)
16182708Swollman					while (i > 0 &&
16192708Swollman						sp->lsis[i].ls_trans ==
16202708Swollman						sp->lsis[i - 1].ls_trans + 1 &&
16212708Swollman						sp->lsis[i].ls_corr ==
16222708Swollman						sp->lsis[i - 1].ls_corr + 1) {
16232708Swollman							++hit;
16242708Swollman							--i;
16252708Swollman					}
16262708Swollman			}
16272708Swollman			corr = lp->ls_corr;
16282708Swollman			break;
16292708Swollman		}
16302708Swollman	}
1631192625Sedwin	y = EPOCH_YEAR;
1632192625Sedwin	tdays = *timep / SECSPERDAY;
1633192625Sedwin	rem = *timep - tdays * SECSPERDAY;
1634192625Sedwin	while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1635192625Sedwin		int		newy;
1636192625Sedwin		register time_t	tdelta;
1637192625Sedwin		register int	idelta;
1638192625Sedwin		register int	leapdays;
1639192625Sedwin
1640192625Sedwin		tdelta = tdays / DAYSPERLYEAR;
1641192625Sedwin		idelta = tdelta;
1642192625Sedwin		if (tdelta - idelta >= 1 || idelta - tdelta >= 1)
1643192625Sedwin			return NULL;
1644192625Sedwin		if (idelta == 0)
1645192625Sedwin			idelta = (tdays < 0) ? -1 : 1;
1646192625Sedwin		newy = y;
1647192625Sedwin		if (increment_overflow(&newy, idelta))
1648192625Sedwin			return NULL;
1649192625Sedwin		leapdays = leaps_thru_end_of(newy - 1) -
1650192625Sedwin			leaps_thru_end_of(y - 1);
1651192625Sedwin		tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1652192625Sedwin		tdays -= leapdays;
1653192625Sedwin		y = newy;
16542708Swollman	}
1655192625Sedwin	{
1656192625Sedwin		register long	seconds;
1657192625Sedwin
1658192625Sedwin		seconds = tdays * SECSPERDAY + 0.5;
1659192625Sedwin		tdays = seconds / SECSPERDAY;
1660192625Sedwin		rem += seconds - tdays * SECSPERDAY;
1661192625Sedwin	}
1662192625Sedwin	/*
1663192625Sedwin	** Given the range, we can now fearlessly cast...
1664192625Sedwin	*/
1665192625Sedwin	idays = tdays;
1666192625Sedwin	rem += offset - corr;
16672708Swollman	while (rem < 0) {
16682708Swollman		rem += SECSPERDAY;
1669192625Sedwin		--idays;
16702708Swollman	}
16712708Swollman	while (rem >= SECSPERDAY) {
16722708Swollman		rem -= SECSPERDAY;
1673192625Sedwin		++idays;
16742708Swollman	}
1675192625Sedwin	while (idays < 0) {
1676192625Sedwin		if (increment_overflow(&y, -1))
1677192625Sedwin			return NULL;
1678192625Sedwin		idays += year_lengths[isleap(y)];
1679192625Sedwin	}
1680192625Sedwin	while (idays >= year_lengths[isleap(y)]) {
1681192625Sedwin		idays -= year_lengths[isleap(y)];
1682192625Sedwin		if (increment_overflow(&y, 1))
1683192625Sedwin			return NULL;
1684192625Sedwin	}
1685192625Sedwin	tmp->tm_year = y;
1686192625Sedwin	if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1687192625Sedwin		return NULL;
1688192625Sedwin	tmp->tm_yday = idays;
1689192625Sedwin	/*
1690192625Sedwin	** The "extra" mods below avoid overflow problems.
1691192625Sedwin	*/
1692192625Sedwin	tmp->tm_wday = EPOCH_WDAY +
1693192625Sedwin		((y - EPOCH_YEAR) % DAYSPERWEEK) *
1694192625Sedwin		(DAYSPERNYEAR % DAYSPERWEEK) +
1695192625Sedwin		leaps_thru_end_of(y - 1) -
1696192625Sedwin		leaps_thru_end_of(EPOCH_YEAR - 1) +
1697192625Sedwin		idays;
1698192625Sedwin	tmp->tm_wday %= DAYSPERWEEK;
1699192625Sedwin	if (tmp->tm_wday < 0)
1700192625Sedwin		tmp->tm_wday += DAYSPERWEEK;
17012708Swollman	tmp->tm_hour = (int) (rem / SECSPERHOUR);
1702192625Sedwin	rem %= SECSPERHOUR;
17032708Swollman	tmp->tm_min = (int) (rem / SECSPERMIN);
170417209Swollman	/*
170517209Swollman	** A positive leap second requires a special
1706192625Sedwin	** representation. This uses "... ??:59:60" et seq.
170717209Swollman	*/
170817209Swollman	tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1709192625Sedwin	ip = mon_lengths[isleap(y)];
1710192625Sedwin	for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1711192625Sedwin		idays -= ip[tmp->tm_mon];
1712192625Sedwin	tmp->tm_mday = (int) (idays + 1);
17132708Swollman	tmp->tm_isdst = 0;
17142708Swollman#ifdef TM_GMTOFF
17152708Swollman	tmp->TM_GMTOFF = offset;
17162708Swollman#endif /* defined TM_GMTOFF */
1717192625Sedwin	return tmp;
17182708Swollman}
17192708Swollman
17202708Swollmanchar *
17212708Swollmanctime(timep)
17222708Swollmanconst time_t * const	timep;
17232708Swollman{
17249936Swollman/*
17259936Swollman** Section 4.12.3.2 of X3.159-1989 requires that
1726130461Sstefanf**	The ctime function converts the calendar time pointed to by timer
1727192625Sedwin**	to local time in the form of a string. It is equivalent to
17289936Swollman**		asctime(localtime(timer))
17299936Swollman*/
17302708Swollman	return asctime(localtime(timep));
17312708Swollman}
17322708Swollman
173335285Sphkchar *
173435285Sphkctime_r(timep, buf)
173535285Sphkconst time_t * const	timep;
1736130461Sstefanfchar *			buf;
173735285Sphk{
1738192625Sedwin	struct tm	mytm;
1739130461Sstefanf
1740192625Sedwin	return asctime_r(localtime_r(timep, &mytm), buf);
174135285Sphk}
174235285Sphk
17432708Swollman/*
17442708Swollman** Adapted from code provided by Robert Elz, who writes:
17452708Swollman**	The "best" way to do mktime I think is based on an idea of Bob
174617209Swollman**	Kridle's (so its said...) from a long time ago.
1747192625Sedwin**	It does a binary search of the time_t space. Since time_t's are
17482708Swollman**	just 32 bits, its a max of 32 iterations (even at 64 bits it
17492708Swollman**	would still be very reasonable).
17502708Swollman*/
17512708Swollman
17522708Swollman#ifndef WRONG
17532708Swollman#define WRONG	(-1)
17542708Swollman#endif /* !defined WRONG */
17552708Swollman
17562708Swollman/*
1757192625Sedwin** Simplified normalize logic courtesy Paul Eggert.
17582708Swollman*/
17592708Swollman
17602708Swollmanstatic int
17612708Swollmanincrement_overflow(number, delta)
17622708Swollmanint *	number;
17632708Swollmanint	delta;
17642708Swollman{
17659936Swollman	int	number0;
17668870Srgrimes
17672708Swollman	number0 = *number;
17682708Swollman	*number += delta;
17692708Swollman	return (*number < number0) != (delta < 0);
17702708Swollman}
17712708Swollman
17722708Swollmanstatic int
1773192625Sedwinlong_increment_overflow(number, delta)
1774192625Sedwinlong *	number;
1775192625Sedwinint	delta;
1776192625Sedwin{
1777192625Sedwin	long	number0;
1778192625Sedwin
1779192625Sedwin	number0 = *number;
1780192625Sedwin	*number += delta;
1781192625Sedwin	return (*number < number0) != (delta < 0);
1782192625Sedwin}
1783192625Sedwin
1784192625Sedwinstatic int
17852708Swollmannormalize_overflow(tensptr, unitsptr, base)
17862708Swollmanint * const	tensptr;
17872708Swollmanint * const	unitsptr;
17882708Swollmanconst int	base;
17892708Swollman{
179092889Sobrien	int	tensdelta;
17912708Swollman
17922708Swollman	tensdelta = (*unitsptr >= 0) ?
17932708Swollman		(*unitsptr / base) :
17942708Swollman		(-1 - (-1 - *unitsptr) / base);
17952708Swollman	*unitsptr -= tensdelta * base;
17962708Swollman	return increment_overflow(tensptr, tensdelta);
17972708Swollman}
17982708Swollman
17992708Swollmanstatic int
1800192625Sedwinlong_normalize_overflow(tensptr, unitsptr, base)
1801192625Sedwinlong * const	tensptr;
1802192625Sedwinint * const	unitsptr;
1803192625Sedwinconst int	base;
1804192625Sedwin{
1805192625Sedwin	register int	tensdelta;
1806192625Sedwin
1807192625Sedwin	tensdelta = (*unitsptr >= 0) ?
1808192625Sedwin		(*unitsptr / base) :
1809192625Sedwin		(-1 - (-1 - *unitsptr) / base);
1810192625Sedwin	*unitsptr -= tensdelta * base;
1811192625Sedwin	return long_increment_overflow(tensptr, tensdelta);
1812192625Sedwin}
1813192625Sedwin
1814192625Sedwinstatic int
18152708Swollmantmcomp(atmp, btmp)
181692889Sobrienconst struct tm * const atmp;
181792889Sobrienconst struct tm * const btmp;
18182708Swollman{
181992889Sobrien	int	result;
18202708Swollman
18212708Swollman	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
18222708Swollman		(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
18232708Swollman		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
18242708Swollman		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
18252708Swollman		(result = (atmp->tm_min - btmp->tm_min)) == 0)
18262708Swollman			result = atmp->tm_sec - btmp->tm_sec;
18272708Swollman	return result;
18282708Swollman}
18292708Swollman
18302708Swollmanstatic time_t
1831130461Sstefanftime2sub(tmp, funcp, offset, okayp, do_norm_secs)
18322708Swollmanstruct tm * const	tmp;
1833192625Sedwinstruct tm * (* const	funcp)(const time_t*, long, struct tm*);
18342708Swollmanconst long		offset;
18352708Swollmanint * const		okayp;
1836130461Sstefanfconst int		do_norm_secs;
18372708Swollman{
183892889Sobrien	const struct state *	sp;
183992889Sobrien	int			dir;
1840192625Sedwin	int			i, j;
184192889Sobrien	int			saved_seconds;
1842192625Sedwin	long			li;
1843192625Sedwin	time_t			lo;
1844192625Sedwin	time_t			hi;
1845192625Sedwin	long			y;
1846192625Sedwin	time_t			newt;
1847192625Sedwin	time_t			t;
1848192625Sedwin	struct tm		yourtm, mytm;
18492708Swollman
18502708Swollman	*okayp = FALSE;
18512708Swollman	yourtm = *tmp;
1852130461Sstefanf	if (do_norm_secs) {
1853130461Sstefanf		if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1854130461Sstefanf			SECSPERMIN))
1855130461Sstefanf				return WRONG;
1856130461Sstefanf	}
18572708Swollman	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
18582708Swollman		return WRONG;
18592708Swollman	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
18602708Swollman		return WRONG;
1861192625Sedwin	y = yourtm.tm_year;
1862192625Sedwin	if (long_normalize_overflow(&y, &yourtm.tm_mon, MONSPERYEAR))
18632708Swollman		return WRONG;
18642708Swollman	/*
1865192625Sedwin	** Turn y into an actual year number for now.
18662708Swollman	** It is converted back to an offset from TM_YEAR_BASE later.
18672708Swollman	*/
1868192625Sedwin	if (long_increment_overflow(&y, TM_YEAR_BASE))
18692708Swollman		return WRONG;
18702708Swollman	while (yourtm.tm_mday <= 0) {
1871192625Sedwin		if (long_increment_overflow(&y, -1))
18722708Swollman			return WRONG;
1873192625Sedwin		li = y + (1 < yourtm.tm_mon);
1874192625Sedwin		yourtm.tm_mday += year_lengths[isleap(li)];
18752708Swollman	}
18762708Swollman	while (yourtm.tm_mday > DAYSPERLYEAR) {
1877192625Sedwin		li = y + (1 < yourtm.tm_mon);
1878192625Sedwin		yourtm.tm_mday -= year_lengths[isleap(li)];
1879192625Sedwin		if (long_increment_overflow(&y, 1))
18802708Swollman			return WRONG;
18812708Swollman	}
18822708Swollman	for ( ; ; ) {
1883192625Sedwin		i = mon_lengths[isleap(y)][yourtm.tm_mon];
18842708Swollman		if (yourtm.tm_mday <= i)
18852708Swollman			break;
18862708Swollman		yourtm.tm_mday -= i;
18872708Swollman		if (++yourtm.tm_mon >= MONSPERYEAR) {
18882708Swollman			yourtm.tm_mon = 0;
1889192625Sedwin			if (long_increment_overflow(&y, 1))
18902708Swollman				return WRONG;
18912708Swollman		}
18922708Swollman	}
1893192625Sedwin	if (long_increment_overflow(&y, -TM_YEAR_BASE))
18942708Swollman		return WRONG;
1895192625Sedwin	yourtm.tm_year = y;
1896192625Sedwin	if (yourtm.tm_year != y)
1897192625Sedwin		return WRONG;
1898134231Speter	/* Don't go below 1900 for POLA */
1899134231Speter	if (yourtm.tm_year < 0)
1900134231Speter		return WRONG;
190177785Swollman	if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
190277785Swollman		saved_seconds = 0;
1903192625Sedwin	else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
19042708Swollman		/*
19052708Swollman		** We can't set tm_sec to 0, because that might push the
19062708Swollman		** time below the minimum representable time.
19072708Swollman		** Set tm_sec to 59 instead.
19082708Swollman		** This assumes that the minimum representable time is
19092708Swollman		** not in the same minute that a leap second was deleted from,
19102708Swollman		** which is a safer assumption than using 58 would be.
19112708Swollman		*/
19122708Swollman		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
19132708Swollman			return WRONG;
19142708Swollman		saved_seconds = yourtm.tm_sec;
19152708Swollman		yourtm.tm_sec = SECSPERMIN - 1;
19162708Swollman	} else {
19172708Swollman		saved_seconds = yourtm.tm_sec;
19182708Swollman		yourtm.tm_sec = 0;
19192708Swollman	}
19202708Swollman	/*
1921192625Sedwin	** Do a binary search (this works whatever time_t's type is).
19222708Swollman	*/
1923192625Sedwin	if (!TYPE_SIGNED(time_t)) {
1924192625Sedwin		lo = 0;
1925192625Sedwin		hi = lo - 1;
1926192625Sedwin	} else if (!TYPE_INTEGRAL(time_t)) {
1927192625Sedwin		if (sizeof(time_t) > sizeof(float))
1928192625Sedwin			hi = (time_t) DBL_MAX;
1929192625Sedwin		else	hi = (time_t) FLT_MAX;
1930192625Sedwin		lo = -hi;
1931192625Sedwin	} else {
1932192625Sedwin		lo = 1;
1933192625Sedwin		for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
1934192625Sedwin			lo *= 2;
1935192625Sedwin		hi = -(lo + 1);
1936192625Sedwin	}
19372708Swollman	for ( ; ; ) {
1938192625Sedwin		t = lo / 2 + hi / 2;
1939192625Sedwin		if (t < lo)
1940192625Sedwin			t = lo;
1941192625Sedwin		else if (t > hi)
1942192625Sedwin			t = hi;
1943192625Sedwin		if ((*funcp)(&t, offset, &mytm) == NULL) {
1944192625Sedwin			/*
1945192625Sedwin			** Assume that t is too extreme to be represented in
1946192625Sedwin			** a struct tm; arrange things so that it is less
1947192625Sedwin			** extreme on the next pass.
1948192625Sedwin			*/
1949192625Sedwin			dir = (t > 0) ? 1 : -1;
1950192625Sedwin		} else	dir = tmcomp(&mytm, &yourtm);
19512708Swollman		if (dir != 0) {
1952192625Sedwin			if (t == lo) {
1953192625Sedwin				++t;
1954192625Sedwin				if (t <= lo)
1955192625Sedwin					return WRONG;
1956192625Sedwin				++lo;
1957192625Sedwin			} else if (t == hi) {
1958192625Sedwin				--t;
1959192625Sedwin				if (t >= hi)
1960192625Sedwin					return WRONG;
1961192625Sedwin				--hi;
1962192625Sedwin			}
1963192625Sedwin			if (lo > hi)
19642708Swollman				return WRONG;
1965192625Sedwin			if (dir > 0)
1966192625Sedwin				hi = t;
1967192625Sedwin			else	lo = t;
19682708Swollman			continue;
19692708Swollman		}
19702708Swollman		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
19712708Swollman			break;
19722708Swollman		/*
19732708Swollman		** Right time, wrong type.
19742708Swollman		** Hunt for right time, right type.
19752708Swollman		** It's okay to guess wrong since the guess
19762708Swollman		** gets checked.
19772708Swollman		*/
1978192625Sedwin		sp = (const struct state *)
1979192625Sedwin			((funcp == localsub) ? lclptr : gmtptr);
19802708Swollman#ifdef ALL_STATE
19812708Swollman		if (sp == NULL)
19822708Swollman			return WRONG;
19832708Swollman#endif /* defined ALL_STATE */
198417209Swollman		for (i = sp->typecnt - 1; i >= 0; --i) {
19852708Swollman			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
19862708Swollman				continue;
198717209Swollman			for (j = sp->typecnt - 1; j >= 0; --j) {
19882708Swollman				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
19892708Swollman					continue;
19902708Swollman				newt = t + sp->ttis[j].tt_gmtoff -
19912708Swollman					sp->ttis[i].tt_gmtoff;
1992192625Sedwin				if ((*funcp)(&newt, offset, &mytm) == NULL)
1993192625Sedwin					continue;
19942708Swollman				if (tmcomp(&mytm, &yourtm) != 0)
19952708Swollman					continue;
19962708Swollman				if (mytm.tm_isdst != yourtm.tm_isdst)
19972708Swollman					continue;
19982708Swollman				/*
19992708Swollman				** We have a match.
20002708Swollman				*/
20012708Swollman				t = newt;
20022708Swollman				goto label;
20032708Swollman			}
20042708Swollman		}
20052708Swollman		return WRONG;
20062708Swollman	}
20072708Swollmanlabel:
20082708Swollman	newt = t + saved_seconds;
20092708Swollman	if ((newt < t) != (saved_seconds < 0))
20102708Swollman		return WRONG;
20112708Swollman	t = newt;
2012192625Sedwin	if ((*funcp)(&t, offset, tmp))
2013192625Sedwin		*okayp = TRUE;
20142708Swollman	return t;
20152708Swollman}
20162708Swollman
20172708Swollmanstatic time_t
2018130461Sstefanftime2(tmp, funcp, offset, okayp)
2019130461Sstefanfstruct tm * const	tmp;
2020192625Sedwinstruct tm * (* const	funcp)(const time_t*, long, struct tm*);
2021130461Sstefanfconst long		offset;
2022130461Sstefanfint * const		okayp;
2023130461Sstefanf{
2024130461Sstefanf	time_t	t;
2025130461Sstefanf
2026130461Sstefanf	/*
2027130461Sstefanf	** First try without normalization of seconds
2028130461Sstefanf	** (in case tm_sec contains a value associated with a leap second).
2029130461Sstefanf	** If that fails, try with normalization of seconds.
2030130461Sstefanf	*/
2031130461Sstefanf	t = time2sub(tmp, funcp, offset, okayp, FALSE);
2032130461Sstefanf	return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE);
2033130461Sstefanf}
2034130461Sstefanf
2035130461Sstefanfstatic time_t
20362708Swollmantime1(tmp, funcp, offset)
20372708Swollmanstruct tm * const	tmp;
2038192625Sedwinstruct tm * (* const  funcp)(const time_t *, long, struct tm *);
20392708Swollmanconst long		offset;
20402708Swollman{
204192889Sobrien	time_t			t;
204292889Sobrien	const struct state *	sp;
204392889Sobrien	int			samei, otheri;
2044130461Sstefanf	int			sameind, otherind;
2045130461Sstefanf	int			i;
2046130461Sstefanf	int			nseen;
2047130461Sstefanf	int				seen[TZ_MAX_TYPES];
2048130461Sstefanf	int				types[TZ_MAX_TYPES];
20492708Swollman	int				okay;
20502708Swollman
20512708Swollman	if (tmp->tm_isdst > 1)
20522708Swollman		tmp->tm_isdst = 1;
20532708Swollman	t = time2(tmp, funcp, offset, &okay);
20542708Swollman#ifdef PCTS
20552708Swollman	/*
2056192625Sedwin	** PCTS code courtesy Grant Sullivan.
20572708Swollman	*/
20582708Swollman	if (okay)
20592708Swollman		return t;
20602708Swollman	if (tmp->tm_isdst < 0)
20612708Swollman		tmp->tm_isdst = 0;	/* reset to std and try again */
20622708Swollman#endif /* defined PCTS */
20632708Swollman#ifndef PCTS
20642708Swollman	if (okay || tmp->tm_isdst < 0)
20652708Swollman		return t;
20662708Swollman#endif /* !defined PCTS */
20672708Swollman	/*
20682708Swollman	** We're supposed to assume that somebody took a time of one type
20692708Swollman	** and did some math on it that yielded a "struct tm" that's bad.
20702708Swollman	** We try to divine the type they started from and adjust to the
20712708Swollman	** type they need.
20722708Swollman	*/
2073192625Sedwin	sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
20742708Swollman#ifdef ALL_STATE
20752708Swollman	if (sp == NULL)
20762708Swollman		return WRONG;
20772708Swollman#endif /* defined ALL_STATE */
2078130461Sstefanf	for (i = 0; i < sp->typecnt; ++i)
2079130461Sstefanf		seen[i] = FALSE;
2080130461Sstefanf	nseen = 0;
2081130461Sstefanf	for (i = sp->timecnt - 1; i >= 0; --i)
2082130461Sstefanf		if (!seen[sp->types[i]]) {
2083130461Sstefanf			seen[sp->types[i]] = TRUE;
2084130461Sstefanf			types[nseen++] = sp->types[i];
2085130461Sstefanf		}
2086130461Sstefanf	for (sameind = 0; sameind < nseen; ++sameind) {
2087130461Sstefanf		samei = types[sameind];
20882708Swollman		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
20892708Swollman			continue;
2090130461Sstefanf		for (otherind = 0; otherind < nseen; ++otherind) {
2091130461Sstefanf			otheri = types[otherind];
20922708Swollman			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
20932708Swollman				continue;
20942708Swollman			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
20952708Swollman					sp->ttis[samei].tt_gmtoff;
20962708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
20972708Swollman			t = time2(tmp, funcp, offset, &okay);
20982708Swollman			if (okay)
20992708Swollman				return t;
21002708Swollman			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
21012708Swollman					sp->ttis[samei].tt_gmtoff;
21022708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
21032708Swollman		}
21042708Swollman	}
21052708Swollman	return WRONG;
21062708Swollman}
21072708Swollman
21082708Swollmantime_t
21092708Swollmanmktime(tmp)
21102708Swollmanstruct tm * const	tmp;
21112708Swollman{
211213545Sjulian	time_t mktime_return_value;
2113177824Sdavidxu	_RWLOCK_RDLOCK(&lcl_rwlock);
2114177824Sdavidxu	tzset_basic(1);
211513545Sjulian	mktime_return_value = time1(tmp, localsub, 0L);
2116177824Sdavidxu	_RWLOCK_UNLOCK(&lcl_rwlock);
211713545Sjulian	return(mktime_return_value);
21182708Swollman}
21192708Swollman
21202708Swollman#ifdef STD_INSPIRED
21212708Swollman
21222708Swollmantime_t
21232708Swollmantimelocal(tmp)
21242708Swollmanstruct tm * const	tmp;
21252708Swollman{
21262708Swollman	tmp->tm_isdst = -1;	/* in case it wasn't initialized */
21272708Swollman	return mktime(tmp);
21282708Swollman}
21292708Swollman
21302708Swollmantime_t
21312708Swollmantimegm(tmp)
21322708Swollmanstruct tm * const	tmp;
21332708Swollman{
21342708Swollman	tmp->tm_isdst = 0;
21352708Swollman	return time1(tmp, gmtsub, 0L);
21362708Swollman}
21372708Swollman
21382708Swollmantime_t
21392708Swollmantimeoff(tmp, offset)
21402708Swollmanstruct tm * const	tmp;
21412708Swollmanconst long		offset;
21422708Swollman{
21432708Swollman	tmp->tm_isdst = 0;
21442708Swollman	return time1(tmp, gmtsub, offset);
21452708Swollman}
21462708Swollman
21472708Swollman#endif /* defined STD_INSPIRED */
21482708Swollman
21492708Swollman#ifdef CMUCS
21502708Swollman
21512708Swollman/*
21522708Swollman** The following is supplied for compatibility with
21532708Swollman** previous versions of the CMUCS runtime library.
21542708Swollman*/
21552708Swollman
21562708Swollmanlong
21572708Swollmangtime(tmp)
21582708Swollmanstruct tm * const	tmp;
21592708Swollman{
21602708Swollman	const time_t	t = mktime(tmp);
21612708Swollman
21622708Swollman	if (t == WRONG)
21632708Swollman		return -1;
21642708Swollman	return t;
21652708Swollman}
21662708Swollman
21672708Swollman#endif /* defined CMUCS */
21682708Swollman
21692708Swollman/*
21702708Swollman** XXX--is the below the right way to conditionalize??
21712708Swollman*/
21722708Swollman
21732708Swollman#ifdef STD_INSPIRED
21742708Swollman
21752708Swollman/*
21762708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2177130461Sstefanf** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
21782708Swollman** is not the case if we are accounting for leap seconds.
21792708Swollman** So, we provide the following conversion routines for use
21802708Swollman** when exchanging timestamps with POSIX conforming systems.
21812708Swollman*/
21822708Swollman
21832708Swollmanstatic long
21842708Swollmanleapcorr(timep)
21852708Swollmantime_t *	timep;
21862708Swollman{
218792889Sobrien	struct state *		sp;
218892889Sobrien	struct lsinfo *	lp;
218992889Sobrien	int			i;
21902708Swollman
21912708Swollman	sp = lclptr;
21922708Swollman	i = sp->leapcnt;
21932708Swollman	while (--i >= 0) {
21942708Swollman		lp = &sp->lsis[i];
21952708Swollman		if (*timep >= lp->ls_trans)
21962708Swollman			return lp->ls_corr;
21972708Swollman	}
21982708Swollman	return 0;
21992708Swollman}
22002708Swollman
22012708Swollmantime_t
22022708Swollmantime2posix(t)
22032708Swollmantime_t	t;
22042708Swollman{
22059936Swollman	tzset();
22062708Swollman	return t - leapcorr(&t);
22072708Swollman}
22082708Swollman
22092708Swollmantime_t
22102708Swollmanposix2time(t)
22112708Swollmantime_t	t;
22122708Swollman{
22132708Swollman	time_t	x;
22142708Swollman	time_t	y;
22152708Swollman
22169936Swollman	tzset();
22172708Swollman	/*
22182708Swollman	** For a positive leap second hit, the result
2219192625Sedwin	** is not unique. For a negative leap second
22202708Swollman	** hit, the corresponding time doesn't exist,
22212708Swollman	** so we return an adjacent second.
22222708Swollman	*/
22232708Swollman	x = t + leapcorr(&t);
22242708Swollman	y = x - leapcorr(&x);
22252708Swollman	if (y < t) {
22262708Swollman		do {
22272708Swollman			x++;
22282708Swollman			y = x - leapcorr(&x);
22292708Swollman		} while (y < t);
22302708Swollman		if (t != y)
22312708Swollman			return x - 1;
22322708Swollman	} else if (y > t) {
22332708Swollman		do {
22342708Swollman			--x;
22352708Swollman			y = x - leapcorr(&x);
22362708Swollman		} while (y > t);
22372708Swollman		if (t != y)
22382708Swollman			return x + 1;
22392708Swollman	}
22402708Swollman	return x;
22412708Swollman}
22422708Swollman
22432708Swollman#endif /* defined STD_INSPIRED */
2244