localtime.c revision 17209
117209Swollman/*
217209Swollman** This file is in the public domain, so clarified as of
317209Swollman** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov).
417209Swollman*/
515923Sscrappy
62708Swollman#ifndef lint
72708Swollman#ifndef NOID
817209Swollmanstatic char	elsieid[] = "@(#)localtime.c	7.57";
92708Swollman#endif /* !defined NOID */
102708Swollman#endif /* !defined lint */
112708Swollman
122708Swollman/*
132708Swollman** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
142708Swollman** POSIX-style TZ environment variable handling from Guy Harris
152708Swollman** (guy@auspex.com).
162708Swollman*/
172708Swollman
182708Swollman/*LINTLIBRARY*/
192708Swollman
202708Swollman#include "private.h"
212708Swollman#include "tzfile.h"
222708Swollman#include "fcntl.h"
2313545Sjulian#ifdef	_THREAD_SAFE
2413545Sjulian#include <pthread.h>
2513545Sjulian#include "pthread_private.h"
2613545Sjulian#endif
272708Swollman
289936Swollman/*
299936Swollman** SunOS 4.1.1 headers lack O_BINARY.
309936Swollman*/
312708Swollman
322708Swollman#ifdef O_BINARY
332708Swollman#define OPEN_MODE	(O_RDONLY | O_BINARY)
342708Swollman#endif /* defined O_BINARY */
352708Swollman#ifndef O_BINARY
362708Swollman#define OPEN_MODE	O_RDONLY
372708Swollman#endif /* !defined O_BINARY */
382708Swollman
392708Swollman#ifndef WILDABBR
402708Swollman/*
412708Swollman** Someone might make incorrect use of a time zone abbreviation:
422708Swollman**	1.	They might reference tzname[0] before calling tzset (explicitly
439936Swollman**		or implicitly).
442708Swollman**	2.	They might reference tzname[1] before calling tzset (explicitly
459936Swollman**		or implicitly).
462708Swollman**	3.	They might reference tzname[1] after setting to a time zone
472708Swollman**		in which Daylight Saving Time is never observed.
482708Swollman**	4.	They might reference tzname[0] after setting to a time zone
492708Swollman**		in which Standard Time is never observed.
502708Swollman**	5.	They might reference tm.TM_ZONE after calling offtime.
512708Swollman** What's best to do in the above cases is open to debate;
522708Swollman** for now, we just set things up so that in any of the five cases
532708Swollman** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
542708Swollman** string "tzname[0] used before set", and similarly for the other cases.
552708Swollman** And another:  initialize tzname[0] to "ERA", with an explanation in the
562708Swollman** manual page of what this "time zone abbreviation" means (doing this so
572708Swollman** that tzname[0] has the "normal" length of three characters).
582708Swollman*/
592708Swollman#define WILDABBR	"   "
602708Swollman#endif /* !defined WILDABBR */
612708Swollman
629936Swollmanstatic char		wildabbr[] = "WILDABBR";
632708Swollman
649936Swollmanstatic const char	gmt[] = "GMT";
659936Swollman
662708Swollmanstruct ttinfo {				/* time type information */
672708Swollman	long		tt_gmtoff;	/* GMT offset in seconds */
682708Swollman	int		tt_isdst;	/* used to set tm_isdst */
692708Swollman	int		tt_abbrind;	/* abbreviation list index */
702708Swollman	int		tt_ttisstd;	/* TRUE if transition is std time */
719936Swollman	int		tt_ttisgmt;	/* TRUE if transition is GMT */
722708Swollman};
732708Swollman
742708Swollmanstruct lsinfo {				/* leap second information */
752708Swollman	time_t		ls_trans;	/* transition time */
762708Swollman	long		ls_corr;	/* correction to apply */
772708Swollman};
782708Swollman
792708Swollman#define BIGGEST(a, b)	(((a) > (b)) ? (a) : (b))
802708Swollman
812708Swollman#ifdef TZNAME_MAX
822708Swollman#define MY_TZNAME_MAX	TZNAME_MAX
832708Swollman#endif /* defined TZNAME_MAX */
842708Swollman#ifndef TZNAME_MAX
852708Swollman#define MY_TZNAME_MAX	255
862708Swollman#endif /* !defined TZNAME_MAX */
872708Swollman
882708Swollmanstruct state {
892708Swollman	int		leapcnt;
902708Swollman	int		timecnt;
912708Swollman	int		typecnt;
922708Swollman	int		charcnt;
932708Swollman	time_t		ats[TZ_MAX_TIMES];
942708Swollman	unsigned char	types[TZ_MAX_TIMES];
952708Swollman	struct ttinfo	ttis[TZ_MAX_TYPES];
969936Swollman	char		chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
972708Swollman				(2 * (MY_TZNAME_MAX + 1)))];
982708Swollman	struct lsinfo	lsis[TZ_MAX_LEAPS];
992708Swollman};
1002708Swollman
1012708Swollmanstruct rule {
1022708Swollman	int		r_type;		/* type of rule--see below */
1032708Swollman	int		r_day;		/* day number of rule */
1042708Swollman	int		r_week;		/* week number of rule */
1052708Swollman	int		r_mon;		/* month number of rule */
1062708Swollman	long		r_time;		/* transition time of rule */
1072708Swollman};
1082708Swollman
1092708Swollman#define JULIAN_DAY		0	/* Jn - Julian day */
1102708Swollman#define DAY_OF_YEAR		1	/* n - day of year */
1112708Swollman#define MONTH_NTH_DAY_OF_WEEK	2	/* Mm.n.d - month, week, day of week */
1122708Swollman
1132708Swollman/*
1142708Swollman** Prototypes for static functions.
1152708Swollman*/
1162708Swollman
1172708Swollmanstatic long		detzcode P((const char * codep));
1182708Swollmanstatic const char *	getzname P((const char * strp));
1192708Swollmanstatic const char *	getnum P((const char * strp, int * nump, int min,
1202708Swollman				int max));
1212708Swollmanstatic const char *	getsecs P((const char * strp, long * secsp));
1222708Swollmanstatic const char *	getoffset P((const char * strp, long * offsetp));
1232708Swollmanstatic const char *	getrule P((const char * strp, struct rule * rulep));
1242708Swollmanstatic void		gmtload P((struct state * sp));
1252708Swollmanstatic void		gmtsub P((const time_t * timep, long offset,
1262708Swollman				struct tm * tmp));
1272708Swollmanstatic void		localsub P((const time_t * timep, long offset,
1282708Swollman				struct tm * tmp));
1292708Swollmanstatic int		increment_overflow P((int * number, int delta));
1302708Swollmanstatic int		normalize_overflow P((int * tensptr, int * unitsptr,
1312708Swollman				int base));
1322708Swollmanstatic void		settzname P((void));
1339936Swollmanstatic time_t		time1 P((struct tm * tmp,
1349936Swollman				void(*funcp) P((const time_t *,
1359936Swollman				long, struct tm *)),
1362708Swollman				long offset));
1379936Swollmanstatic time_t		time2 P((struct tm *tmp,
1389936Swollman				void(*funcp) P((const time_t *,
1399936Swollman				long, struct tm*)),
1402708Swollman				long offset, int * okayp));
1412708Swollmanstatic void		timesub P((const time_t * timep, long offset,
1422708Swollman				const struct state * sp, struct tm * tmp));
1432708Swollmanstatic int		tmcomp P((const struct tm * atmp,
1442708Swollman				const struct tm * btmp));
1452708Swollmanstatic time_t		transtime P((time_t janfirst, int year,
1462708Swollman				const struct rule * rulep, long offset));
1472708Swollmanstatic int		tzload P((const char * name, struct state * sp));
1482708Swollmanstatic int		tzparse P((const char * name, struct state * sp,
1492708Swollman				int lastditch));
1502708Swollman
1512708Swollman#ifdef ALL_STATE
1522708Swollmanstatic struct state *	lclptr;
1532708Swollmanstatic struct state *	gmtptr;
1542708Swollman#endif /* defined ALL_STATE */
1552708Swollman
1562708Swollman#ifndef ALL_STATE
1572708Swollmanstatic struct state	lclmem;
1582708Swollmanstatic struct state	gmtmem;
1592708Swollman#define lclptr		(&lclmem)
1602708Swollman#define gmtptr		(&gmtmem)
1612708Swollman#endif /* State Farm */
1622708Swollman
1639936Swollman#ifndef TZ_STRLEN_MAX
1649936Swollman#define TZ_STRLEN_MAX 255
1659936Swollman#endif /* !defined TZ_STRLEN_MAX */
1669936Swollman
1679936Swollmanstatic char		lcl_TZname[TZ_STRLEN_MAX + 1];
1682708Swollmanstatic int		lcl_is_set;
1692708Swollmanstatic int		gmt_is_set;
17013545Sjulian#ifdef	_THREAD_SAFE
17113545Sjulianstatic pthread_mutex_t  lcl_mutex   = PTHREAD_MUTEX_INITIALIZER;
17213545Sjulianstatic pthread_mutex_t  gmt_mutex   = PTHREAD_MUTEX_INITIALIZER;
17313545Sjulian#endif
1742708Swollman
1752708Swollmanchar *			tzname[2] = {
1769936Swollman	wildabbr,
1779936Swollman	wildabbr
1782708Swollman};
1792708Swollman
1809936Swollman/*
1819936Swollman** Section 4.12.3 of X3.159-1989 requires that
1829936Swollman**	Except for the strftime function, these functions [asctime,
1839936Swollman**	ctime, gmtime, localtime] return values in one of two static
1849936Swollman**	objects: a broken-down time structure and an array of char.
1859936Swollman** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
1869936Swollman*/
1879936Swollman
1889936Swollmanstatic struct tm	tm;
1899936Swollman
1902708Swollman#ifdef USG_COMPAT
1912708Swollmantime_t			timezone = 0;
1922708Swollmanint			daylight = 0;
1932708Swollman#endif /* defined USG_COMPAT */
1942708Swollman
1952708Swollman#ifdef ALTZONE
1962708Swollmantime_t			altzone = 0;
1972708Swollman#endif /* defined ALTZONE */
1982708Swollman
1992708Swollmanstatic long
2002708Swollmandetzcode(codep)
2012708Swollmanconst char * const	codep;
2022708Swollman{
2032708Swollman	register long	result;
2042708Swollman	register int	i;
2052708Swollman
20617209Swollman	result = (codep[0] & 0x80) ? ~0L : 0L;
2072708Swollman	for (i = 0; i < 4; ++i)
2082708Swollman		result = (result << 8) | (codep[i] & 0xff);
2092708Swollman	return result;
2102708Swollman}
2112708Swollman
2122708Swollmanstatic void
2139936Swollmansettzname P((void))
2142708Swollman{
21517209Swollman	register struct state * const	sp = lclptr;
21617209Swollman	register int			i;
2172708Swollman
2189936Swollman	tzname[0] = wildabbr;
2199936Swollman	tzname[1] = wildabbr;
2202708Swollman#ifdef USG_COMPAT
2212708Swollman	daylight = 0;
2222708Swollman	timezone = 0;
2232708Swollman#endif /* defined USG_COMPAT */
2242708Swollman#ifdef ALTZONE
2252708Swollman	altzone = 0;
2262708Swollman#endif /* defined ALTZONE */
2272708Swollman#ifdef ALL_STATE
2282708Swollman	if (sp == NULL) {
2299936Swollman		tzname[0] = tzname[1] = gmt;
2302708Swollman		return;
2312708Swollman	}
2322708Swollman#endif /* defined ALL_STATE */
2332708Swollman	for (i = 0; i < sp->typecnt; ++i) {
2342708Swollman		register const struct ttinfo * const	ttisp = &sp->ttis[i];
2352708Swollman
2362708Swollman		tzname[ttisp->tt_isdst] =
2379936Swollman			&sp->chars[ttisp->tt_abbrind];
2382708Swollman#ifdef USG_COMPAT
2392708Swollman		if (ttisp->tt_isdst)
2402708Swollman			daylight = 1;
2412708Swollman		if (i == 0 || !ttisp->tt_isdst)
2422708Swollman			timezone = -(ttisp->tt_gmtoff);
2432708Swollman#endif /* defined USG_COMPAT */
2442708Swollman#ifdef ALTZONE
2452708Swollman		if (i == 0 || ttisp->tt_isdst)
2462708Swollman			altzone = -(ttisp->tt_gmtoff);
2472708Swollman#endif /* defined ALTZONE */
2482708Swollman	}
2492708Swollman	/*
2502708Swollman	** And to get the latest zone names into tzname. . .
2512708Swollman	*/
2522708Swollman	for (i = 0; i < sp->timecnt; ++i) {
2532708Swollman		register const struct ttinfo * const	ttisp =
2542708Swollman							&sp->ttis[
2552708Swollman								sp->types[i]];
2562708Swollman
2572708Swollman		tzname[ttisp->tt_isdst] =
2589936Swollman			&sp->chars[ttisp->tt_abbrind];
2592708Swollman	}
2602708Swollman}
2612708Swollman
2622708Swollmanstatic int
2632708Swollmantzload(name, sp)
2642708Swollmanregister const char *		name;
2652708Swollmanregister struct state * const	sp;
2662708Swollman{
2672708Swollman	register const char *	p;
2682708Swollman	register int		i;
2692708Swollman	register int		fid;
2702708Swollman
2712708Swollman	if (name == NULL && (name = TZDEFAULT) == NULL)
2722708Swollman		return -1;
2732708Swollman	{
2749936Swollman		register int	doaccess;
2759936Swollman		/*
2769936Swollman		** Section 4.9.1 of the C standard says that
2779936Swollman		** "FILENAME_MAX expands to an integral constant expression
2789936Swollman		** that is the sie needed for an array of char large enough
2799936Swollman		** to hold the longest file name string that the implementation
2809936Swollman		** guarantees can be opened."
2819936Swollman		*/
2822708Swollman		char		fullname[FILENAME_MAX + 1];
2832708Swollman
2842708Swollman		if (name[0] == ':')
2852708Swollman			++name;
2862708Swollman		doaccess = name[0] == '/';
2872708Swollman		if (!doaccess) {
2882708Swollman			if ((p = TZDIR) == NULL)
2892708Swollman				return -1;
2902708Swollman			if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
2912708Swollman				return -1;
2922708Swollman			(void) strcpy(fullname, p);
2932708Swollman			(void) strcat(fullname, "/");
2942708Swollman			(void) strcat(fullname, name);
2952708Swollman			/*
2962708Swollman			** Set doaccess if '.' (as in "../") shows up in name.
2972708Swollman			*/
2982708Swollman			if (strchr(name, '.') != NULL)
2992708Swollman				doaccess = TRUE;
3002708Swollman			name = fullname;
3012708Swollman		}
3029936Swollman		if (doaccess && access(name, R_OK) != 0)
3032708Swollman			return -1;
3042708Swollman		if ((fid = open(name, OPEN_MODE)) == -1)
3052708Swollman			return -1;
3062708Swollman	}
3072708Swollman	{
3089936Swollman		struct tzhead *	tzhp;
3099936Swollman		char		buf[sizeof *sp + sizeof *tzhp];
3109936Swollman		int		ttisstdcnt;
3119936Swollman		int		ttisgmtcnt;
3122708Swollman
3132708Swollman		i = read(fid, buf, sizeof buf);
3149936Swollman		if (close(fid) != 0)
3152708Swollman			return -1;
3169936Swollman		p = buf;
3179936Swollman		p += sizeof tzhp->tzh_reserved;
3189936Swollman		ttisstdcnt = (int) detzcode(p);
3199936Swollman		p += 4;
3209936Swollman		ttisgmtcnt = (int) detzcode(p);
3219936Swollman		p += 4;
3229936Swollman		sp->leapcnt = (int) detzcode(p);
3239936Swollman		p += 4;
3249936Swollman		sp->timecnt = (int) detzcode(p);
3259936Swollman		p += 4;
3269936Swollman		sp->typecnt = (int) detzcode(p);
3279936Swollman		p += 4;
3289936Swollman		sp->charcnt = (int) detzcode(p);
3299936Swollman		p += 4;
3302708Swollman		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
3312708Swollman			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
3322708Swollman			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
3332708Swollman			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
3349936Swollman			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
3359936Swollman			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
3362708Swollman				return -1;
3379936Swollman		if (i - (p - buf) < sp->timecnt * 4 +	/* ats */
3389936Swollman			sp->timecnt +			/* types */
3399936Swollman			sp->typecnt * (4 + 2) +		/* ttinfos */
3409936Swollman			sp->charcnt +			/* chars */
3419936Swollman			sp->leapcnt * (4 + 4) +		/* lsinfos */
3429936Swollman			ttisstdcnt +			/* ttisstds */
3439936Swollman			ttisgmtcnt)			/* ttisgmts */
3442708Swollman				return -1;
3452708Swollman		for (i = 0; i < sp->timecnt; ++i) {
3462708Swollman			sp->ats[i] = detzcode(p);
3472708Swollman			p += 4;
3482708Swollman		}
3492708Swollman		for (i = 0; i < sp->timecnt; ++i) {
3502708Swollman			sp->types[i] = (unsigned char) *p++;
3512708Swollman			if (sp->types[i] >= sp->typecnt)
3522708Swollman				return -1;
3532708Swollman		}
3542708Swollman		for (i = 0; i < sp->typecnt; ++i) {
3552708Swollman			register struct ttinfo *	ttisp;
3562708Swollman
3572708Swollman			ttisp = &sp->ttis[i];
3582708Swollman			ttisp->tt_gmtoff = detzcode(p);
3592708Swollman			p += 4;
3602708Swollman			ttisp->tt_isdst = (unsigned char) *p++;
3612708Swollman			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
3622708Swollman				return -1;
3632708Swollman			ttisp->tt_abbrind = (unsigned char) *p++;
3642708Swollman			if (ttisp->tt_abbrind < 0 ||
3652708Swollman				ttisp->tt_abbrind > sp->charcnt)
3662708Swollman					return -1;
3672708Swollman		}
3682708Swollman		for (i = 0; i < sp->charcnt; ++i)
3692708Swollman			sp->chars[i] = *p++;
3702708Swollman		sp->chars[i] = '\0';	/* ensure '\0' at end */
3712708Swollman		for (i = 0; i < sp->leapcnt; ++i) {
3722708Swollman			register struct lsinfo *	lsisp;
3732708Swollman
3742708Swollman			lsisp = &sp->lsis[i];
3752708Swollman			lsisp->ls_trans = detzcode(p);
3762708Swollman			p += 4;
3772708Swollman			lsisp->ls_corr = detzcode(p);
3782708Swollman			p += 4;
3792708Swollman		}
3802708Swollman		for (i = 0; i < sp->typecnt; ++i) {
3812708Swollman			register struct ttinfo *	ttisp;
3822708Swollman
3832708Swollman			ttisp = &sp->ttis[i];
3842708Swollman			if (ttisstdcnt == 0)
3852708Swollman				ttisp->tt_ttisstd = FALSE;
3862708Swollman			else {
3872708Swollman				ttisp->tt_ttisstd = *p++;
3882708Swollman				if (ttisp->tt_ttisstd != TRUE &&
3892708Swollman					ttisp->tt_ttisstd != FALSE)
3902708Swollman						return -1;
3912708Swollman			}
3922708Swollman		}
3939936Swollman		for (i = 0; i < sp->typecnt; ++i) {
3949936Swollman			register struct ttinfo *	ttisp;
3959936Swollman
3969936Swollman			ttisp = &sp->ttis[i];
3979936Swollman			if (ttisgmtcnt == 0)
3989936Swollman				ttisp->tt_ttisgmt = FALSE;
3999936Swollman			else {
4009936Swollman				ttisp->tt_ttisgmt = *p++;
4019936Swollman				if (ttisp->tt_ttisgmt != TRUE &&
4029936Swollman					ttisp->tt_ttisgmt != FALSE)
4039936Swollman						return -1;
4049936Swollman			}
4059936Swollman		}
4062708Swollman	}
4072708Swollman	return 0;
4082708Swollman}
4092708Swollman
4102708Swollmanstatic const int	mon_lengths[2][MONSPERYEAR] = {
4112708Swollman	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
4122708Swollman	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
4132708Swollman};
4142708Swollman
4152708Swollmanstatic const int	year_lengths[2] = {
4162708Swollman	DAYSPERNYEAR, DAYSPERLYEAR
4172708Swollman};
4182708Swollman
4192708Swollman/*
4202708Swollman** Given a pointer into a time zone string, scan until a character that is not
4212708Swollman** a valid character in a zone name is found.  Return a pointer to that
4222708Swollman** character.
4232708Swollman*/
4242708Swollman
4252708Swollmanstatic const char *
4262708Swollmangetzname(strp)
4272708Swollmanregister const char *	strp;
4282708Swollman{
4292708Swollman	register char	c;
4302708Swollman
43117209Swollman	while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
4322708Swollman		c != '+')
4332708Swollman			++strp;
4342708Swollman	return strp;
4352708Swollman}
4362708Swollman
4372708Swollman/*
4382708Swollman** Given a pointer into a time zone string, extract a number from that string.
4392708Swollman** Check that the number is within a specified range; if it is not, return
4402708Swollman** NULL.
4412708Swollman** Otherwise, return a pointer to the first character not part of the number.
4422708Swollman*/
4432708Swollman
4442708Swollmanstatic const char *
4452708Swollmangetnum(strp, nump, min, max)
4462708Swollmanregister const char *	strp;
4472708Swollmanint * const		nump;
4482708Swollmanconst int		min;
4492708Swollmanconst int		max;
4502708Swollman{
4512708Swollman	register char	c;
4522708Swollman	register int	num;
4532708Swollman
45417209Swollman	if (strp == NULL || !is_digit(c = *strp))
4552708Swollman		return NULL;
4562708Swollman	num = 0;
45717209Swollman	do {
4582708Swollman		num = num * 10 + (c - '0');
4592708Swollman		if (num > max)
4602708Swollman			return NULL;	/* illegal value */
46117209Swollman		c = *++strp;
46217209Swollman	} while (is_digit(c));
4632708Swollman	if (num < min)
4642708Swollman		return NULL;		/* illegal value */
4652708Swollman	*nump = num;
4662708Swollman	return strp;
4672708Swollman}
4682708Swollman
4692708Swollman/*
4702708Swollman** Given a pointer into a time zone string, extract a number of seconds,
4712708Swollman** in hh[:mm[:ss]] form, from the string.
4722708Swollman** If any error occurs, return NULL.
4732708Swollman** Otherwise, return a pointer to the first character not part of the number
4742708Swollman** of seconds.
4752708Swollman*/
4762708Swollman
4772708Swollmanstatic const char *
4782708Swollmangetsecs(strp, secsp)
4792708Swollmanregister const char *	strp;
4802708Swollmanlong * const		secsp;
4812708Swollman{
4822708Swollman	int	num;
4832708Swollman
4849936Swollman	/*
4859936Swollman	** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
4869936Swollman	** "M10.4.6/26", which does not conform to Posix,
4879936Swollman	** but which specifies the equivalent of
4889936Swollman	** ``02:00 on the first Sunday on or after 23 Oct''.
4899936Swollman	*/
4909936Swollman	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
4912708Swollman	if (strp == NULL)
4922708Swollman		return NULL;
4939936Swollman	*secsp = num * (long) SECSPERHOUR;
4942708Swollman	if (*strp == ':') {
4952708Swollman		++strp;
4962708Swollman		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
4972708Swollman		if (strp == NULL)
4982708Swollman			return NULL;
4992708Swollman		*secsp += num * SECSPERMIN;
5002708Swollman		if (*strp == ':') {
5012708Swollman			++strp;
5029936Swollman			/* `SECSPERMIN' allows for leap seconds.  */
5039936Swollman			strp = getnum(strp, &num, 0, SECSPERMIN);
5042708Swollman			if (strp == NULL)
5052708Swollman				return NULL;
5062708Swollman			*secsp += num;
5072708Swollman		}
5082708Swollman	}
5092708Swollman	return strp;
5102708Swollman}
5112708Swollman
5122708Swollman/*
5132708Swollman** Given a pointer into a time zone string, extract an offset, in
5142708Swollman** [+-]hh[:mm[:ss]] form, from the string.
5152708Swollman** If any error occurs, return NULL.
5162708Swollman** Otherwise, return a pointer to the first character not part of the time.
5172708Swollman*/
5182708Swollman
5192708Swollmanstatic const char *
5202708Swollmangetoffset(strp, offsetp)
5212708Swollmanregister const char *	strp;
5222708Swollmanlong * const		offsetp;
5232708Swollman{
52417209Swollman	register int	neg = 0;
5252708Swollman
5262708Swollman	if (*strp == '-') {
5272708Swollman		neg = 1;
5282708Swollman		++strp;
52917209Swollman	} else if (*strp == '+')
53017209Swollman		++strp;
5312708Swollman	strp = getsecs(strp, offsetp);
5322708Swollman	if (strp == NULL)
5332708Swollman		return NULL;		/* illegal time */
5342708Swollman	if (neg)
5352708Swollman		*offsetp = -*offsetp;
5362708Swollman	return strp;
5372708Swollman}
5382708Swollman
5392708Swollman/*
5402708Swollman** Given a pointer into a time zone string, extract a rule in the form
5412708Swollman** date[/time].  See POSIX section 8 for the format of "date" and "time".
5422708Swollman** If a valid rule is not found, return NULL.
5432708Swollman** Otherwise, return a pointer to the first character not part of the rule.
5442708Swollman*/
5452708Swollman
5462708Swollmanstatic const char *
5472708Swollmangetrule(strp, rulep)
5482708Swollmanconst char *			strp;
5492708Swollmanregister struct rule * const	rulep;
5502708Swollman{
5512708Swollman	if (*strp == 'J') {
5522708Swollman		/*
5532708Swollman		** Julian day.
5542708Swollman		*/
5552708Swollman		rulep->r_type = JULIAN_DAY;
5562708Swollman		++strp;
5572708Swollman		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
5582708Swollman	} else if (*strp == 'M') {
5592708Swollman		/*
5602708Swollman		** Month, week, day.
5612708Swollman		*/
5622708Swollman		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
5632708Swollman		++strp;
5642708Swollman		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
5652708Swollman		if (strp == NULL)
5662708Swollman			return NULL;
5672708Swollman		if (*strp++ != '.')
5682708Swollman			return NULL;
5692708Swollman		strp = getnum(strp, &rulep->r_week, 1, 5);
5702708Swollman		if (strp == NULL)
5712708Swollman			return NULL;
5722708Swollman		if (*strp++ != '.')
5732708Swollman			return NULL;
5742708Swollman		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
57517209Swollman	} else if (is_digit(*strp)) {
5762708Swollman		/*
5772708Swollman		** Day of year.
5782708Swollman		*/
5792708Swollman		rulep->r_type = DAY_OF_YEAR;
5802708Swollman		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
5812708Swollman	} else	return NULL;		/* invalid format */
5822708Swollman	if (strp == NULL)
5832708Swollman		return NULL;
5842708Swollman	if (*strp == '/') {
5852708Swollman		/*
5862708Swollman		** Time specified.
5872708Swollman		*/
5882708Swollman		++strp;
5892708Swollman		strp = getsecs(strp, &rulep->r_time);
5902708Swollman	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
5912708Swollman	return strp;
5922708Swollman}
5932708Swollman
5942708Swollman/*
5952708Swollman** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
5962708Swollman** year, a rule, and the offset from GMT at the time that rule takes effect,
5972708Swollman** calculate the Epoch-relative time that rule takes effect.
5982708Swollman*/
5992708Swollman
6002708Swollmanstatic time_t
6012708Swollmantranstime(janfirst, year, rulep, offset)
6022708Swollmanconst time_t				janfirst;
6032708Swollmanconst int				year;
6042708Swollmanregister const struct rule * const	rulep;
6052708Swollmanconst long				offset;
6062708Swollman{
6072708Swollman	register int	leapyear;
6082708Swollman	register time_t	value;
6092708Swollman	register int	i;
6102708Swollman	int		d, m1, yy0, yy1, yy2, dow;
6112708Swollman
6129936Swollman	INITIALIZE(value);
6132708Swollman	leapyear = isleap(year);
6142708Swollman	switch (rulep->r_type) {
6152708Swollman
6162708Swollman	case JULIAN_DAY:
6172708Swollman		/*
6182708Swollman		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
6192708Swollman		** years.
6202708Swollman		** In non-leap years, or if the day number is 59 or less, just
6212708Swollman		** add SECSPERDAY times the day number-1 to the time of
6222708Swollman		** January 1, midnight, to get the day.
6232708Swollman		*/
6242708Swollman		value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
6252708Swollman		if (leapyear && rulep->r_day >= 60)
6262708Swollman			value += SECSPERDAY;
6272708Swollman		break;
6282708Swollman
6292708Swollman	case DAY_OF_YEAR:
6302708Swollman		/*
6312708Swollman		** n - day of year.
6322708Swollman		** Just add SECSPERDAY times the day number to the time of
6332708Swollman		** January 1, midnight, to get the day.
6342708Swollman		*/
6352708Swollman		value = janfirst + rulep->r_day * SECSPERDAY;
6362708Swollman		break;
6372708Swollman
6382708Swollman	case MONTH_NTH_DAY_OF_WEEK:
6392708Swollman		/*
6402708Swollman		** Mm.n.d - nth "dth day" of month m.
6412708Swollman		*/
6422708Swollman		value = janfirst;
6432708Swollman		for (i = 0; i < rulep->r_mon - 1; ++i)
6442708Swollman			value += mon_lengths[leapyear][i] * SECSPERDAY;
6452708Swollman
6462708Swollman		/*
6472708Swollman		** Use Zeller's Congruence to get day-of-week of first day of
6482708Swollman		** month.
6492708Swollman		*/
6502708Swollman		m1 = (rulep->r_mon + 9) % 12 + 1;
6512708Swollman		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
6522708Swollman		yy1 = yy0 / 100;
6532708Swollman		yy2 = yy0 % 100;
6542708Swollman		dow = ((26 * m1 - 2) / 10 +
6552708Swollman			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
6562708Swollman		if (dow < 0)
6572708Swollman			dow += DAYSPERWEEK;
6582708Swollman
6592708Swollman		/*
6602708Swollman		** "dow" is the day-of-week of the first day of the month.  Get
6612708Swollman		** the day-of-month (zero-origin) of the first "dow" day of the
6622708Swollman		** month.
6632708Swollman		*/
6642708Swollman		d = rulep->r_day - dow;
6652708Swollman		if (d < 0)
6662708Swollman			d += DAYSPERWEEK;
6672708Swollman		for (i = 1; i < rulep->r_week; ++i) {
6682708Swollman			if (d + DAYSPERWEEK >=
6692708Swollman				mon_lengths[leapyear][rulep->r_mon - 1])
6702708Swollman					break;
6712708Swollman			d += DAYSPERWEEK;
6722708Swollman		}
6732708Swollman
6742708Swollman		/*
6752708Swollman		** "d" is the day-of-month (zero-origin) of the day we want.
6762708Swollman		*/
6772708Swollman		value += d * SECSPERDAY;
6782708Swollman		break;
6792708Swollman	}
6802708Swollman
6812708Swollman	/*
6822708Swollman	** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
6832708Swollman	** question.  To get the Epoch-relative time of the specified local
6842708Swollman	** time on that day, add the transition time and the current offset
6852708Swollman	** from GMT.
6862708Swollman	*/
6872708Swollman	return value + rulep->r_time + offset;
6882708Swollman}
6892708Swollman
6902708Swollman/*
6912708Swollman** Given a POSIX section 8-style TZ string, fill in the rule tables as
6922708Swollman** appropriate.
6932708Swollman*/
6942708Swollman
6952708Swollmanstatic int
6962708Swollmantzparse(name, sp, lastditch)
6972708Swollmanconst char *			name;
6982708Swollmanregister struct state * const	sp;
6992708Swollmanconst int			lastditch;
7002708Swollman{
7012708Swollman	const char *			stdname;
7022708Swollman	const char *			dstname;
7039936Swollman	size_t				stdlen;
7049936Swollman	size_t				dstlen;
7052708Swollman	long				stdoffset;
7062708Swollman	long				dstoffset;
7072708Swollman	register time_t *		atp;
7082708Swollman	register unsigned char *	typep;
7092708Swollman	register char *			cp;
7102708Swollman	register int			load_result;
7112708Swollman
7129936Swollman	INITIALIZE(dstname);
7132708Swollman	stdname = name;
7142708Swollman	if (lastditch) {
7152708Swollman		stdlen = strlen(name);	/* length of standard zone name */
7162708Swollman		name += stdlen;
7172708Swollman		if (stdlen >= sizeof sp->chars)
7182708Swollman			stdlen = (sizeof sp->chars) - 1;
7192708Swollman	} else {
7202708Swollman		name = getzname(name);
7212708Swollman		stdlen = name - stdname;
7222708Swollman		if (stdlen < 3)
7232708Swollman			return -1;
7242708Swollman	}
7252708Swollman	if (*name == '\0')
7262708Swollman		return -1;	/* was "stdoffset = 0;" */
7272708Swollman	else {
7282708Swollman		name = getoffset(name, &stdoffset);
7292708Swollman		if (name == NULL)
7302708Swollman			return -1;
7312708Swollman	}
7322708Swollman	load_result = tzload(TZDEFRULES, sp);
7332708Swollman	if (load_result != 0)
7342708Swollman		sp->leapcnt = 0;		/* so, we're off a little */
7352708Swollman	if (*name != '\0') {
7362708Swollman		dstname = name;
7372708Swollman		name = getzname(name);
7382708Swollman		dstlen = name - dstname;	/* length of DST zone name */
7392708Swollman		if (dstlen < 3)
7402708Swollman			return -1;
7412708Swollman		if (*name != '\0' && *name != ',' && *name != ';') {
7422708Swollman			name = getoffset(name, &dstoffset);
7432708Swollman			if (name == NULL)
7442708Swollman				return -1;
7452708Swollman		} else	dstoffset = stdoffset - SECSPERHOUR;
7462708Swollman		if (*name == ',' || *name == ';') {
7472708Swollman			struct rule	start;
7482708Swollman			struct rule	end;
7492708Swollman			register int	year;
7502708Swollman			register time_t	janfirst;
7512708Swollman			time_t		starttime;
7522708Swollman			time_t		endtime;
7532708Swollman
7542708Swollman			++name;
7552708Swollman			if ((name = getrule(name, &start)) == NULL)
7562708Swollman				return -1;
7572708Swollman			if (*name++ != ',')
7582708Swollman				return -1;
7592708Swollman			if ((name = getrule(name, &end)) == NULL)
7602708Swollman				return -1;
7612708Swollman			if (*name != '\0')
7622708Swollman				return -1;
7632708Swollman			sp->typecnt = 2;	/* standard time and DST */
7642708Swollman			/*
7652708Swollman			** Two transitions per year, from EPOCH_YEAR to 2037.
7662708Swollman			*/
7672708Swollman			sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
7682708Swollman			if (sp->timecnt > TZ_MAX_TIMES)
7692708Swollman				return -1;
7702708Swollman			sp->ttis[0].tt_gmtoff = -dstoffset;
7712708Swollman			sp->ttis[0].tt_isdst = 1;
7722708Swollman			sp->ttis[0].tt_abbrind = stdlen + 1;
7732708Swollman			sp->ttis[1].tt_gmtoff = -stdoffset;
7742708Swollman			sp->ttis[1].tt_isdst = 0;
7752708Swollman			sp->ttis[1].tt_abbrind = 0;
7762708Swollman			atp = sp->ats;
7772708Swollman			typep = sp->types;
7782708Swollman			janfirst = 0;
7792708Swollman			for (year = EPOCH_YEAR; year <= 2037; ++year) {
7802708Swollman				starttime = transtime(janfirst, year, &start,
7812708Swollman					stdoffset);
7822708Swollman				endtime = transtime(janfirst, year, &end,
7832708Swollman					dstoffset);
7842708Swollman				if (starttime > endtime) {
7852708Swollman					*atp++ = endtime;
7862708Swollman					*typep++ = 1;	/* DST ends */
7872708Swollman					*atp++ = starttime;
7882708Swollman					*typep++ = 0;	/* DST begins */
7892708Swollman				} else {
7902708Swollman					*atp++ = starttime;
7912708Swollman					*typep++ = 0;	/* DST begins */
7922708Swollman					*atp++ = endtime;
7932708Swollman					*typep++ = 1;	/* DST ends */
7942708Swollman				}
7952708Swollman				janfirst += year_lengths[isleap(year)] *
7962708Swollman					SECSPERDAY;
7972708Swollman			}
7982708Swollman		} else {
7999936Swollman			register long	theirstdoffset;
8009936Swollman			register long	theirdstoffset;
8019936Swollman			register long	theiroffset;
8029936Swollman			register int	isdst;
8032708Swollman			register int	i;
8049936Swollman			register int	j;
8052708Swollman
8062708Swollman			if (*name != '\0')
8072708Swollman				return -1;
8082708Swollman			if (load_result != 0)
8092708Swollman				return -1;
8102708Swollman			/*
8119936Swollman			** Initial values of theirstdoffset and theirdstoffset.
8122708Swollman			*/
8139936Swollman			theirstdoffset = 0;
8149936Swollman			for (i = 0; i < sp->timecnt; ++i) {
8159936Swollman				j = sp->types[i];
8169936Swollman				if (!sp->ttis[j].tt_isdst) {
81717209Swollman					theirstdoffset =
81817209Swollman						-sp->ttis[j].tt_gmtoff;
8199936Swollman					break;
8202708Swollman				}
8212708Swollman			}
8229936Swollman			theirdstoffset = 0;
8239936Swollman			for (i = 0; i < sp->timecnt; ++i) {
8249936Swollman				j = sp->types[i];
8259936Swollman				if (sp->ttis[j].tt_isdst) {
82617209Swollman					theirdstoffset =
82717209Swollman						-sp->ttis[j].tt_gmtoff;
8289936Swollman					break;
8299936Swollman				}
8309936Swollman			}
8312708Swollman			/*
8329936Swollman			** Initially we're assumed to be in standard time.
8332708Swollman			*/
8349936Swollman			isdst = FALSE;
8359936Swollman			theiroffset = theirstdoffset;
8362708Swollman			/*
8379936Swollman			** Now juggle transition times and types
8389936Swollman			** tracking offsets as you do.
8392708Swollman			*/
8402708Swollman			for (i = 0; i < sp->timecnt; ++i) {
8419936Swollman				j = sp->types[i];
8429936Swollman				sp->types[i] = sp->ttis[j].tt_isdst;
8439936Swollman				if (sp->ttis[j].tt_ttisgmt) {
8449936Swollman					/* No adjustment to transition time */
8459936Swollman				} else {
8469936Swollman					/*
8479936Swollman					** If summer time is in effect, and the
8489936Swollman					** transition time was not specified as
8499936Swollman					** standard time, add the summer time
8509936Swollman					** offset to the transition time;
8519936Swollman					** otherwise, add the standard time
8529936Swollman					** offset to the transition time.
8539936Swollman					*/
8549936Swollman					/*
8559936Swollman					** Transitions from DST to DDST
8569936Swollman					** will effectively disappear since
8579936Swollman					** POSIX provides for only one DST
8589936Swollman					** offset.
8599936Swollman					*/
8609936Swollman					if (isdst && !sp->ttis[j].tt_ttisstd) {
8619936Swollman						sp->ats[i] += dstoffset -
8629936Swollman							theirdstoffset;
8639936Swollman					} else {
8649936Swollman						sp->ats[i] += stdoffset -
8659936Swollman							theirstdoffset;
8669936Swollman					}
8679936Swollman				}
8689936Swollman				theiroffset = -sp->ttis[j].tt_gmtoff;
8699936Swollman				if (sp->ttis[j].tt_isdst)
8709936Swollman					theirdstoffset = theiroffset;
8719936Swollman				else	theirstdoffset = theiroffset;
8722708Swollman			}
8739936Swollman			/*
8749936Swollman			** Finally, fill in ttis.
8759936Swollman			** ttisstd and ttisgmt need not be handled.
8769936Swollman			*/
8779936Swollman			sp->ttis[0].tt_gmtoff = -stdoffset;
8789936Swollman			sp->ttis[0].tt_isdst = FALSE;
8799936Swollman			sp->ttis[0].tt_abbrind = 0;
8809936Swollman			sp->ttis[1].tt_gmtoff = -dstoffset;
8819936Swollman			sp->ttis[1].tt_isdst = TRUE;
8829936Swollman			sp->ttis[1].tt_abbrind = stdlen + 1;
8832708Swollman		}
8842708Swollman	} else {
8852708Swollman		dstlen = 0;
8862708Swollman		sp->typecnt = 1;		/* only standard time */
8872708Swollman		sp->timecnt = 0;
8882708Swollman		sp->ttis[0].tt_gmtoff = -stdoffset;
8892708Swollman		sp->ttis[0].tt_isdst = 0;
8902708Swollman		sp->ttis[0].tt_abbrind = 0;
8912708Swollman	}
8922708Swollman	sp->charcnt = stdlen + 1;
8932708Swollman	if (dstlen != 0)
8942708Swollman		sp->charcnt += dstlen + 1;
8952708Swollman	if (sp->charcnt > sizeof sp->chars)
8962708Swollman		return -1;
8972708Swollman	cp = sp->chars;
8982708Swollman	(void) strncpy(cp, stdname, stdlen);
8992708Swollman	cp += stdlen;
9002708Swollman	*cp++ = '\0';
9012708Swollman	if (dstlen != 0) {
9022708Swollman		(void) strncpy(cp, dstname, dstlen);
9032708Swollman		*(cp + dstlen) = '\0';
9042708Swollman	}
9052708Swollman	return 0;
9062708Swollman}
9072708Swollman
9082708Swollmanstatic void
9092708Swollmangmtload(sp)
9102708Swollmanstruct state * const	sp;
9112708Swollman{
9129936Swollman	if (tzload(gmt, sp) != 0)
9139936Swollman		(void) tzparse(gmt, sp, TRUE);
9142708Swollman}
9152708Swollman
9162708Swollman#ifndef STD_INSPIRED
9179936Swollman/*
9189936Swollman** A non-static declaration of tzsetwall in a system header file
9199936Swollman** may cause a warning about this upcoming static declaration...
9209936Swollman*/
9212708Swollmanstatic
9222708Swollman#endif /* !defined STD_INSPIRED */
92313545Sjulian#ifdef	_THREAD_SAFE
9242708Swollmanvoid
92513545Sjuliantzsetwall_basic P((void))
92613545Sjulian#else
92713545Sjulianvoid
9289936Swollmantzsetwall P((void))
92913545Sjulian#endif
9302708Swollman{
9319936Swollman	if (lcl_is_set < 0)
9329936Swollman		return;
9339936Swollman	lcl_is_set = -1;
9349936Swollman
9352708Swollman#ifdef ALL_STATE
9362708Swollman	if (lclptr == NULL) {
9372708Swollman		lclptr = (struct state *) malloc(sizeof *lclptr);
9382708Swollman		if (lclptr == NULL) {
9392708Swollman			settzname();	/* all we can do */
9402708Swollman			return;
9412708Swollman		}
9422708Swollman	}
9432708Swollman#endif /* defined ALL_STATE */
9442708Swollman	if (tzload((char *) NULL, lclptr) != 0)
9452708Swollman		gmtload(lclptr);
9462708Swollman	settzname();
9472708Swollman}
9482708Swollman
94913545Sjulian#ifdef	_THREAD_SAFE
9502708Swollmanvoid
95113545Sjuliantzsetwall P((void))
95213545Sjulian{
95313545Sjulian	pthread_mutex_lock(&lcl_mutex);
95413545Sjulian	tzsetwall_basic();
95513545Sjulian	pthread_mutex_unlock(&lcl_mutex);
95613545Sjulian}
95713545Sjulian#endif
95813545Sjulian
95913545Sjulian#ifdef	_THREAD_SAFE
96013545Sjulianstatic void
96113545Sjuliantzset_basic P((void))
96213545Sjulian#else
96313545Sjulianvoid
9649936Swollmantzset P((void))
96513545Sjulian#endif
9662708Swollman{
9672708Swollman	register const char *	name;
9682708Swollman
9692708Swollman	name = getenv("TZ");
9702708Swollman	if (name == NULL) {
9712708Swollman		tzsetwall();
9722708Swollman		return;
9732708Swollman	}
9749936Swollman
9759936Swollman	if (lcl_is_set > 0  &&  strcmp(lcl_TZname, name) == 0)
9769936Swollman		return;
9779936Swollman	lcl_is_set = (strlen(name) < sizeof(lcl_TZname));
9789936Swollman	if (lcl_is_set)
9799936Swollman		(void) strcpy(lcl_TZname, name);
9809936Swollman
9812708Swollman#ifdef ALL_STATE
9822708Swollman	if (lclptr == NULL) {
9832708Swollman		lclptr = (struct state *) malloc(sizeof *lclptr);
9842708Swollman		if (lclptr == NULL) {
9852708Swollman			settzname();	/* all we can do */
9862708Swollman			return;
9872708Swollman		}
9882708Swollman	}
9892708Swollman#endif /* defined ALL_STATE */
9902708Swollman	if (*name == '\0') {
9912708Swollman		/*
9922708Swollman		** User wants it fast rather than right.
9932708Swollman		*/
9942708Swollman		lclptr->leapcnt = 0;		/* so, we're off a little */
9952708Swollman		lclptr->timecnt = 0;
9962708Swollman		lclptr->ttis[0].tt_gmtoff = 0;
9972708Swollman		lclptr->ttis[0].tt_abbrind = 0;
9989936Swollman		(void) strcpy(lclptr->chars, gmt);
9992708Swollman	} else if (tzload(name, lclptr) != 0)
10002708Swollman		if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
10012708Swollman			(void) gmtload(lclptr);
10022708Swollman	settzname();
10032708Swollman}
10042708Swollman
100513545Sjulian#ifdef	_THREAD_SAFE
100613545Sjulianvoid
100713545Sjuliantzset P((void))
100813545Sjulian{
100913545Sjulian	pthread_mutex_lock(&lcl_mutex);
101013545Sjulian	tzset_basic();
101113545Sjulian	pthread_mutex_unlock(&lcl_mutex);
101213545Sjulian}
101313545Sjulian#endif
101413545Sjulian
10152708Swollman/*
10162708Swollman** The easy way to behave "as if no library function calls" localtime
10172708Swollman** is to not call it--so we drop its guts into "localsub", which can be
10182708Swollman** freely called.  (And no, the PANS doesn't require the above behavior--
10192708Swollman** but it *is* desirable.)
10202708Swollman**
10212708Swollman** The unused offset argument is for the benefit of mktime variants.
10222708Swollman*/
10232708Swollman
10242708Swollman/*ARGSUSED*/
10252708Swollmanstatic void
10262708Swollmanlocalsub(timep, offset, tmp)
10272708Swollmanconst time_t * const	timep;
10282708Swollmanconst long		offset;
10292708Swollmanstruct tm * const	tmp;
10302708Swollman{
10319936Swollman	register struct state *		sp;
10322708Swollman	register const struct ttinfo *	ttisp;
10332708Swollman	register int			i;
10342708Swollman	const time_t			t = *timep;
10352708Swollman
10362708Swollman	sp = lclptr;
10372708Swollman#ifdef ALL_STATE
10382708Swollman	if (sp == NULL) {
10392708Swollman		gmtsub(timep, offset, tmp);
10402708Swollman		return;
10412708Swollman	}
10422708Swollman#endif /* defined ALL_STATE */
10432708Swollman	if (sp->timecnt == 0 || t < sp->ats[0]) {
10442708Swollman		i = 0;
10452708Swollman		while (sp->ttis[i].tt_isdst)
10462708Swollman			if (++i >= sp->typecnt) {
10472708Swollman				i = 0;
10482708Swollman				break;
10492708Swollman			}
10502708Swollman	} else {
10512708Swollman		for (i = 1; i < sp->timecnt; ++i)
10522708Swollman			if (t < sp->ats[i])
10532708Swollman				break;
10542708Swollman		i = sp->types[i - 1];
10552708Swollman	}
10562708Swollman	ttisp = &sp->ttis[i];
10572708Swollman	/*
10582708Swollman	** To get (wrong) behavior that's compatible with System V Release 2.0
10592708Swollman	** you'd replace the statement below with
10602708Swollman	**	t += ttisp->tt_gmtoff;
10612708Swollman	**	timesub(&t, 0L, sp, tmp);
10622708Swollman	*/
10632708Swollman	timesub(&t, ttisp->tt_gmtoff, sp, tmp);
10642708Swollman	tmp->tm_isdst = ttisp->tt_isdst;
10659936Swollman	tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
10662708Swollman#ifdef TM_ZONE
10679936Swollman	tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
10682708Swollman#endif /* defined TM_ZONE */
10692708Swollman}
10702708Swollman
107113545Sjulian#ifdef	_THREAD_SAFE
107213545Sjulianint
107313545Sjulianlocaltime_r(timep, p_tm)
107413545Sjulianconst time_t * const	timep;
107513545Sjulianstruct tm *p_tm;
107613545Sjulian{
107713545Sjulian	pthread_mutex_lock(&lcl_mutex);
107813545Sjulian	tzset();
107913545Sjulian	localsub(timep, 0L, p_tm);
108013545Sjulian	pthread_mutex_unlock(&lcl_mutex);
108113545Sjulian	return(0);
108213545Sjulian}
108313545Sjulian#endif
108413545Sjulian
10852708Swollmanstruct tm *
10862708Swollmanlocaltime(timep)
10872708Swollmanconst time_t * const	timep;
10882708Swollman{
108913545Sjulian#ifdef	_THREAD_SAFE
109013545Sjulian	static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
109113545Sjulian	static pthread_key_t localtime_key = -1;
109213545Sjulian	struct tm *p_tm;
109313545Sjulian
109413545Sjulian	pthread_mutex_lock(&localtime_mutex);
109513545Sjulian	if (localtime_key < 0) {
109613545Sjulian		if (pthread_keycreate(&localtime_key, free) < 0) {
109713545Sjulian			pthread_mutex_unlock(&localtime_mutex);
109813545Sjulian			return(NULL);
109913545Sjulian		}
110013545Sjulian	}
110113545Sjulian	pthread_mutex_unlock(&localtime_mutex);
110213545Sjulian	if (pthread_getspecific(localtime_key,(void **) &p_tm) != 0) {
110313545Sjulian		return(NULL);
110413545Sjulian	} else if (p_tm == NULL) {
110513545Sjulian		if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) {
110613545Sjulian			return(NULL);
110713545Sjulian		}
110813545Sjulian		pthread_setspecific(localtime_key, p_tm);
110913545Sjulian	}
111013545Sjulian	pthread_mutex_lock(&lcl_mutex);
11119936Swollman	tzset();
111213545Sjulian	localsub(timep, 0L, p_tm);
111313545Sjulian	pthread_mutex_unlock(&lcl_mutex);
111413545Sjulian	return p_tm;
111513545Sjulian#else
111613545Sjulian	tzset();
11172708Swollman	localsub(timep, 0L, &tm);
11182708Swollman	return &tm;
111913545Sjulian#endif
11202708Swollman}
11212708Swollman
11222708Swollman/*
11232708Swollman** gmtsub is to gmtime as localsub is to localtime.
11242708Swollman*/
11252708Swollman
11262708Swollmanstatic void
11272708Swollmangmtsub(timep, offset, tmp)
11282708Swollmanconst time_t * const	timep;
11292708Swollmanconst long		offset;
11302708Swollmanstruct tm * const	tmp;
11312708Swollman{
113213545Sjulian#ifdef	_THREAD_SAFE
113313545Sjulian	pthread_mutex_lock(&gmt_mutex);
113413545Sjulian#endif
11352708Swollman	if (!gmt_is_set) {
11362708Swollman		gmt_is_set = TRUE;
11372708Swollman#ifdef ALL_STATE
11382708Swollman		gmtptr = (struct state *) malloc(sizeof *gmtptr);
11392708Swollman		if (gmtptr != NULL)
11402708Swollman#endif /* defined ALL_STATE */
11412708Swollman			gmtload(gmtptr);
11422708Swollman	}
114313545Sjulian#ifdef	_THREAD_SAFE
114413545Sjulian	pthread_mutex_unlock(&gmt_mutex);
114513545Sjulian#endif
11462708Swollman	timesub(timep, offset, gmtptr, tmp);
11472708Swollman#ifdef TM_ZONE
11482708Swollman	/*
11492708Swollman	** Could get fancy here and deliver something such as
11502708Swollman	** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
11512708Swollman	** but this is no time for a treasure hunt.
11522708Swollman	*/
11532708Swollman	if (offset != 0)
11549936Swollman		tmp->TM_ZONE = wildabbr;
11552708Swollman	else {
11562708Swollman#ifdef ALL_STATE
11572708Swollman		if (gmtptr == NULL)
11589936Swollman			tmp->TM_ZONE = gmt;
11592708Swollman		else	tmp->TM_ZONE = gmtptr->chars;
11602708Swollman#endif /* defined ALL_STATE */
11612708Swollman#ifndef ALL_STATE
11622708Swollman		tmp->TM_ZONE = gmtptr->chars;
11632708Swollman#endif /* State Farm */
11642708Swollman	}
11652708Swollman#endif /* defined TM_ZONE */
11662708Swollman}
11672708Swollman
11682708Swollmanstruct tm *
11692708Swollmangmtime(timep)
11702708Swollmanconst time_t * const	timep;
11712708Swollman{
117213545Sjulian#ifdef	_THREAD_SAFE
117313545Sjulian	static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
117413545Sjulian	static pthread_key_t gmtime_key = -1;
117513545Sjulian	struct tm *p_tm;
117613545Sjulian
117713545Sjulian	pthread_mutex_lock(&gmtime_mutex);
117813545Sjulian	if (gmtime_key < 0) {
117913545Sjulian		if (pthread_keycreate(&gmtime_key, free) < 0) {
118013545Sjulian			pthread_mutex_unlock(&gmtime_mutex);
118113545Sjulian			return(NULL);
118213545Sjulian		}
118313545Sjulian	}
118413545Sjulian	pthread_mutex_unlock(&gmtime_mutex);
118513545Sjulian	if (pthread_getspecific(gmtime_key,(void **) &p_tm) != 0) {
118613545Sjulian		return(NULL);
118713545Sjulian	} else if (p_tm == NULL) {
118813545Sjulian		if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) {
118913545Sjulian			return(NULL);
119013545Sjulian		}
119113545Sjulian		pthread_setspecific(gmtime_key, p_tm);
119213545Sjulian	}
119313545Sjulian	gmtsub(timep, 0L, p_tm);
119413545Sjulian	return(p_tm);
119513545Sjulian#else
11962708Swollman	gmtsub(timep, 0L, &tm);
11972708Swollman	return &tm;
119813545Sjulian#endif
11992708Swollman}
12002708Swollman
120113545Sjulian#ifdef	_THREAD_SAFE
120213545Sjulianint
120313545Sjuliangmtime_r(const time_t * timep, struct tm * tm)
120413545Sjulian{
120513545Sjulian	gmtsub(timep, 0L, tm);
120613545Sjulian	return(0);
120713545Sjulian}
120813545Sjulian#endif
120913545Sjulian
12102708Swollman#ifdef STD_INSPIRED
12112708Swollman
12122708Swollmanstruct tm *
12132708Swollmanofftime(timep, offset)
12142708Swollmanconst time_t * const	timep;
12152708Swollmanconst long		offset;
12162708Swollman{
12172708Swollman	gmtsub(timep, offset, &tm);
12182708Swollman	return &tm;
12192708Swollman}
12202708Swollman
12212708Swollman#endif /* defined STD_INSPIRED */
12222708Swollman
12232708Swollmanstatic void
12242708Swollmantimesub(timep, offset, sp, tmp)
12252708Swollmanconst time_t * const			timep;
12262708Swollmanconst long				offset;
12272708Swollmanregister const struct state * const	sp;
12282708Swollmanregister struct tm * const		tmp;
12292708Swollman{
12302708Swollman	register const struct lsinfo *	lp;
12312708Swollman	register long			days;
12322708Swollman	register long			rem;
12332708Swollman	register int			y;
12342708Swollman	register int			yleap;
12352708Swollman	register const int *		ip;
12362708Swollman	register long			corr;
12372708Swollman	register int			hit;
12382708Swollman	register int			i;
12392708Swollman
12402708Swollman	corr = 0;
12412708Swollman	hit = 0;
12422708Swollman#ifdef ALL_STATE
12432708Swollman	i = (sp == NULL) ? 0 : sp->leapcnt;
12442708Swollman#endif /* defined ALL_STATE */
12452708Swollman#ifndef ALL_STATE
12462708Swollman	i = sp->leapcnt;
12472708Swollman#endif /* State Farm */
12482708Swollman	while (--i >= 0) {
12492708Swollman		lp = &sp->lsis[i];
12502708Swollman		if (*timep >= lp->ls_trans) {
12512708Swollman			if (*timep == lp->ls_trans) {
12522708Swollman				hit = ((i == 0 && lp->ls_corr > 0) ||
12532708Swollman					lp->ls_corr > sp->lsis[i - 1].ls_corr);
12542708Swollman				if (hit)
12552708Swollman					while (i > 0 &&
12562708Swollman						sp->lsis[i].ls_trans ==
12572708Swollman						sp->lsis[i - 1].ls_trans + 1 &&
12582708Swollman						sp->lsis[i].ls_corr ==
12592708Swollman						sp->lsis[i - 1].ls_corr + 1) {
12602708Swollman							++hit;
12612708Swollman							--i;
12622708Swollman					}
12632708Swollman			}
12642708Swollman			corr = lp->ls_corr;
12652708Swollman			break;
12662708Swollman		}
12672708Swollman	}
12682708Swollman	days = *timep / SECSPERDAY;
12692708Swollman	rem = *timep % SECSPERDAY;
12702708Swollman#ifdef mc68k
12712708Swollman	if (*timep == 0x80000000) {
12722708Swollman		/*
12732708Swollman		** A 3B1 muffs the division on the most negative number.
12742708Swollman		*/
12752708Swollman		days = -24855;
12762708Swollman		rem = -11648;
12772708Swollman	}
12789936Swollman#endif /* defined mc68k */
12792708Swollman	rem += (offset - corr);
12802708Swollman	while (rem < 0) {
12812708Swollman		rem += SECSPERDAY;
12822708Swollman		--days;
12832708Swollman	}
12842708Swollman	while (rem >= SECSPERDAY) {
12852708Swollman		rem -= SECSPERDAY;
12862708Swollman		++days;
12872708Swollman	}
12882708Swollman	tmp->tm_hour = (int) (rem / SECSPERHOUR);
12892708Swollman	rem = rem % SECSPERHOUR;
12902708Swollman	tmp->tm_min = (int) (rem / SECSPERMIN);
129117209Swollman	/*
129217209Swollman	** A positive leap second requires a special
129317209Swollman	** representation.  This uses "... ??:59:60" et seq.
129417209Swollman	*/
129517209Swollman	tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
12962708Swollman	tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
12972708Swollman	if (tmp->tm_wday < 0)
12982708Swollman		tmp->tm_wday += DAYSPERWEEK;
12992708Swollman	y = EPOCH_YEAR;
130017209Swollman#define LEAPS_THRU_END_OF(y)	((y) / 4 - (y) / 100 + (y) / 400)
130117209Swollman	while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
130217209Swollman		register int	newy;
130317209Swollman
130417209Swollman		newy = y + days / DAYSPERNYEAR;
130517209Swollman		if (days < 0)
130617209Swollman			--newy;
130717209Swollman		days -= (newy - y) * DAYSPERNYEAR +
130817209Swollman			LEAPS_THRU_END_OF(newy - 1) -
130917209Swollman			LEAPS_THRU_END_OF(y - 1);
131017209Swollman		y = newy;
131117209Swollman	}
13122708Swollman	tmp->tm_year = y - TM_YEAR_BASE;
13132708Swollman	tmp->tm_yday = (int) days;
13142708Swollman	ip = mon_lengths[yleap];
13152708Swollman	for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
13162708Swollman		days = days - (long) ip[tmp->tm_mon];
13172708Swollman	tmp->tm_mday = (int) (days + 1);
13182708Swollman	tmp->tm_isdst = 0;
13192708Swollman#ifdef TM_GMTOFF
13202708Swollman	tmp->TM_GMTOFF = offset;
13212708Swollman#endif /* defined TM_GMTOFF */
13222708Swollman}
13232708Swollman
13242708Swollmanchar *
13252708Swollmanctime(timep)
13262708Swollmanconst time_t * const	timep;
13272708Swollman{
13289936Swollman/*
13299936Swollman** Section 4.12.3.2 of X3.159-1989 requires that
13309936Swollman**	The ctime funciton converts the calendar time pointed to by timer
13319936Swollman**	to local time in the form of a string.  It is equivalent to
13329936Swollman**		asctime(localtime(timer))
13339936Swollman*/
13342708Swollman	return asctime(localtime(timep));
13352708Swollman}
13362708Swollman
13372708Swollman/*
13382708Swollman** Adapted from code provided by Robert Elz, who writes:
13392708Swollman**	The "best" way to do mktime I think is based on an idea of Bob
134017209Swollman**	Kridle's (so its said...) from a long time ago.
134117209Swollman**	[kridle@xinet.com as of 1996-01-16.]
13422708Swollman**	It does a binary search of the time_t space.  Since time_t's are
13432708Swollman**	just 32 bits, its a max of 32 iterations (even at 64 bits it
13442708Swollman**	would still be very reasonable).
13452708Swollman*/
13462708Swollman
13472708Swollman#ifndef WRONG
13482708Swollman#define WRONG	(-1)
13492708Swollman#endif /* !defined WRONG */
13502708Swollman
13512708Swollman/*
13522708Swollman** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
13532708Swollman*/
13542708Swollman
13552708Swollmanstatic int
13562708Swollmanincrement_overflow(number, delta)
13572708Swollmanint *	number;
13582708Swollmanint	delta;
13592708Swollman{
13609936Swollman	int	number0;
13618870Srgrimes
13622708Swollman	number0 = *number;
13632708Swollman	*number += delta;
13642708Swollman	return (*number < number0) != (delta < 0);
13652708Swollman}
13662708Swollman
13672708Swollmanstatic int
13682708Swollmannormalize_overflow(tensptr, unitsptr, base)
13692708Swollmanint * const	tensptr;
13702708Swollmanint * const	unitsptr;
13712708Swollmanconst int	base;
13722708Swollman{
13732708Swollman	register int	tensdelta;
13742708Swollman
13752708Swollman	tensdelta = (*unitsptr >= 0) ?
13762708Swollman		(*unitsptr / base) :
13772708Swollman		(-1 - (-1 - *unitsptr) / base);
13782708Swollman	*unitsptr -= tensdelta * base;
13792708Swollman	return increment_overflow(tensptr, tensdelta);
13802708Swollman}
13812708Swollman
13822708Swollmanstatic int
13832708Swollmantmcomp(atmp, btmp)
13842708Swollmanregister const struct tm * const atmp;
13852708Swollmanregister const struct tm * const btmp;
13862708Swollman{
13872708Swollman	register int	result;
13882708Swollman
13892708Swollman	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
13902708Swollman		(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
13912708Swollman		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
13922708Swollman		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
13932708Swollman		(result = (atmp->tm_min - btmp->tm_min)) == 0)
13942708Swollman			result = atmp->tm_sec - btmp->tm_sec;
13952708Swollman	return result;
13962708Swollman}
13972708Swollman
13982708Swollmanstatic time_t
13992708Swollmantime2(tmp, funcp, offset, okayp)
14002708Swollmanstruct tm * const	tmp;
14019936Swollmanvoid (* const		funcp) P((const time_t*, long, struct tm*));
14022708Swollmanconst long		offset;
14032708Swollmanint * const		okayp;
14042708Swollman{
14052708Swollman	register const struct state *	sp;
14062708Swollman	register int			dir;
14072708Swollman	register int			bits;
14082708Swollman	register int			i, j ;
14092708Swollman	register int			saved_seconds;
14102708Swollman	time_t				newt;
14112708Swollman	time_t				t;
14122708Swollman	struct tm			yourtm, mytm;
14132708Swollman
14142708Swollman	*okayp = FALSE;
14152708Swollman	yourtm = *tmp;
14162708Swollman	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
14172708Swollman		return WRONG;
14182708Swollman	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
14192708Swollman		return WRONG;
14202708Swollman	if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
14212708Swollman		return WRONG;
14222708Swollman	/*
14232708Swollman	** Turn yourtm.tm_year into an actual year number for now.
14242708Swollman	** It is converted back to an offset from TM_YEAR_BASE later.
14252708Swollman	*/
14262708Swollman	if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
14272708Swollman		return WRONG;
14282708Swollman	while (yourtm.tm_mday <= 0) {
14292708Swollman		if (increment_overflow(&yourtm.tm_year, -1))
14302708Swollman			return WRONG;
143117209Swollman		i = yourtm.tm_year + (1 < yourtm.tm_mon);
143217209Swollman		yourtm.tm_mday += year_lengths[isleap(i)];
14332708Swollman	}
14342708Swollman	while (yourtm.tm_mday > DAYSPERLYEAR) {
143517209Swollman		i = yourtm.tm_year + (1 < yourtm.tm_mon);
143617209Swollman		yourtm.tm_mday -= year_lengths[isleap(i)];
14372708Swollman		if (increment_overflow(&yourtm.tm_year, 1))
14382708Swollman			return WRONG;
14392708Swollman	}
14402708Swollman	for ( ; ; ) {
14412708Swollman		i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
14422708Swollman		if (yourtm.tm_mday <= i)
14432708Swollman			break;
14442708Swollman		yourtm.tm_mday -= i;
14452708Swollman		if (++yourtm.tm_mon >= MONSPERYEAR) {
14462708Swollman			yourtm.tm_mon = 0;
14472708Swollman			if (increment_overflow(&yourtm.tm_year, 1))
14482708Swollman				return WRONG;
14492708Swollman		}
14502708Swollman	}
14512708Swollman	if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
14522708Swollman		return WRONG;
14532708Swollman	if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
14542708Swollman		/*
14552708Swollman		** We can't set tm_sec to 0, because that might push the
14562708Swollman		** time below the minimum representable time.
14572708Swollman		** Set tm_sec to 59 instead.
14582708Swollman		** This assumes that the minimum representable time is
14592708Swollman		** not in the same minute that a leap second was deleted from,
14602708Swollman		** which is a safer assumption than using 58 would be.
14612708Swollman		*/
14622708Swollman		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
14632708Swollman			return WRONG;
14642708Swollman		saved_seconds = yourtm.tm_sec;
14652708Swollman		yourtm.tm_sec = SECSPERMIN - 1;
14662708Swollman	} else {
14672708Swollman		saved_seconds = yourtm.tm_sec;
14682708Swollman		yourtm.tm_sec = 0;
14692708Swollman	}
14702708Swollman	/*
147117209Swollman	** Divide the search space in half
147217209Swollman	** (this works whether time_t is signed or unsigned).
14732708Swollman	*/
147417209Swollman	bits = TYPE_BIT(time_t) - 1;
14752708Swollman	/*
147617209Swollman	** If time_t is signed, then 0 is just above the median,
147717209Swollman	** assuming two's complement arithmetic.
147817209Swollman	** If time_t is unsigned, then (1 << bits) is just above the median.
14792708Swollman	*/
148017209Swollman	t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits);
14812708Swollman	for ( ; ; ) {
14822708Swollman		(*funcp)(&t, offset, &mytm);
14832708Swollman		dir = tmcomp(&mytm, &yourtm);
14842708Swollman		if (dir != 0) {
14852708Swollman			if (bits-- < 0)
14862708Swollman				return WRONG;
14872708Swollman			if (bits < 0)
148817209Swollman				--t; /* may be needed if new t is minimal */
14892708Swollman			else if (dir > 0)
149017209Swollman				t -= ((time_t) 1) << bits;
149117209Swollman			else	t += ((time_t) 1) << bits;
14922708Swollman			continue;
14932708Swollman		}
14942708Swollman		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
14952708Swollman			break;
14962708Swollman		/*
14972708Swollman		** Right time, wrong type.
14982708Swollman		** Hunt for right time, right type.
14992708Swollman		** It's okay to guess wrong since the guess
15002708Swollman		** gets checked.
15012708Swollman		*/
15022708Swollman		/*
15032708Swollman		** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
15042708Swollman		*/
15052708Swollman		sp = (const struct state *)
15062708Swollman			(((void *) funcp == (void *) localsub) ?
15072708Swollman			lclptr : gmtptr);
15082708Swollman#ifdef ALL_STATE
15092708Swollman		if (sp == NULL)
15102708Swollman			return WRONG;
15112708Swollman#endif /* defined ALL_STATE */
151217209Swollman		for (i = sp->typecnt - 1; i >= 0; --i) {
15132708Swollman			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
15142708Swollman				continue;
151517209Swollman			for (j = sp->typecnt - 1; j >= 0; --j) {
15162708Swollman				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
15172708Swollman					continue;
15182708Swollman				newt = t + sp->ttis[j].tt_gmtoff -
15192708Swollman					sp->ttis[i].tt_gmtoff;
15202708Swollman				(*funcp)(&newt, offset, &mytm);
15212708Swollman				if (tmcomp(&mytm, &yourtm) != 0)
15222708Swollman					continue;
15232708Swollman				if (mytm.tm_isdst != yourtm.tm_isdst)
15242708Swollman					continue;
15252708Swollman				/*
15262708Swollman				** We have a match.
15272708Swollman				*/
15282708Swollman				t = newt;
15292708Swollman				goto label;
15302708Swollman			}
15312708Swollman		}
15322708Swollman		return WRONG;
15332708Swollman	}
15342708Swollmanlabel:
15352708Swollman	newt = t + saved_seconds;
15362708Swollman	if ((newt < t) != (saved_seconds < 0))
15372708Swollman		return WRONG;
15382708Swollman	t = newt;
15392708Swollman	(*funcp)(&t, offset, tmp);
15402708Swollman	*okayp = TRUE;
15412708Swollman	return t;
15422708Swollman}
15432708Swollman
15442708Swollmanstatic time_t
15452708Swollmantime1(tmp, funcp, offset)
15462708Swollmanstruct tm * const	tmp;
154717209Swollmanvoid (* const		funcp) P((const time_t *, long, struct tm *));
15482708Swollmanconst long		offset;
15492708Swollman{
15502708Swollman	register time_t			t;
15512708Swollman	register const struct state *	sp;
15522708Swollman	register int			samei, otheri;
15532708Swollman	int				okay;
15542708Swollman
15552708Swollman	if (tmp->tm_isdst > 1)
15562708Swollman		tmp->tm_isdst = 1;
15572708Swollman	t = time2(tmp, funcp, offset, &okay);
15582708Swollman#ifdef PCTS
15592708Swollman	/*
15602708Swollman	** PCTS code courtesy Grant Sullivan (grant@osf.org).
15612708Swollman	*/
15622708Swollman	if (okay)
15632708Swollman		return t;
15642708Swollman	if (tmp->tm_isdst < 0)
15652708Swollman		tmp->tm_isdst = 0;	/* reset to std and try again */
15662708Swollman#endif /* defined PCTS */
15672708Swollman#ifndef PCTS
15682708Swollman	if (okay || tmp->tm_isdst < 0)
15692708Swollman		return t;
15702708Swollman#endif /* !defined PCTS */
15712708Swollman	/*
15722708Swollman	** We're supposed to assume that somebody took a time of one type
15732708Swollman	** and did some math on it that yielded a "struct tm" that's bad.
15742708Swollman	** We try to divine the type they started from and adjust to the
15752708Swollman	** type they need.
15762708Swollman	*/
15772708Swollman	/*
15782708Swollman	** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
15792708Swollman	*/
15802708Swollman	sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
15812708Swollman		lclptr : gmtptr);
15822708Swollman#ifdef ALL_STATE
15832708Swollman	if (sp == NULL)
15842708Swollman		return WRONG;
15852708Swollman#endif /* defined ALL_STATE */
158617209Swollman	for (samei = sp->typecnt - 1; samei >= 0; --samei) {
15872708Swollman		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
15882708Swollman			continue;
158917209Swollman		for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
15902708Swollman			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
15912708Swollman				continue;
15922708Swollman			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
15932708Swollman					sp->ttis[samei].tt_gmtoff;
15942708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
15952708Swollman			t = time2(tmp, funcp, offset, &okay);
15962708Swollman			if (okay)
15972708Swollman				return t;
15982708Swollman			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
15992708Swollman					sp->ttis[samei].tt_gmtoff;
16002708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
16012708Swollman		}
16022708Swollman	}
16032708Swollman	return WRONG;
16042708Swollman}
16052708Swollman
16062708Swollmantime_t
16072708Swollmanmktime(tmp)
16082708Swollmanstruct tm * const	tmp;
16092708Swollman{
161013545Sjulian	time_t mktime_return_value;
161113545Sjulian#ifdef	_THREAD_SAFE
161213545Sjulian	pthread_mutex_lock(&lcl_mutex);
161313545Sjulian#endif
16149936Swollman	tzset();
161513545Sjulian	mktime_return_value = time1(tmp, localsub, 0L);
161613545Sjulian#ifdef	_THREAD_SAFE
161713545Sjulian	pthread_mutex_unlock(&lcl_mutex);
161813545Sjulian#endif
161913545Sjulian	return(mktime_return_value);
16202708Swollman}
16212708Swollman
16222708Swollman#ifdef STD_INSPIRED
16232708Swollman
16242708Swollmantime_t
16252708Swollmantimelocal(tmp)
16262708Swollmanstruct tm * const	tmp;
16272708Swollman{
16282708Swollman	tmp->tm_isdst = -1;	/* in case it wasn't initialized */
16292708Swollman	return mktime(tmp);
16302708Swollman}
16312708Swollman
16322708Swollmantime_t
16332708Swollmantimegm(tmp)
16342708Swollmanstruct tm * const	tmp;
16352708Swollman{
16362708Swollman	tmp->tm_isdst = 0;
16372708Swollman	return time1(tmp, gmtsub, 0L);
16382708Swollman}
16392708Swollman
16402708Swollmantime_t
16412708Swollmantimeoff(tmp, offset)
16422708Swollmanstruct tm * const	tmp;
16432708Swollmanconst long		offset;
16442708Swollman{
16452708Swollman	tmp->tm_isdst = 0;
16462708Swollman	return time1(tmp, gmtsub, offset);
16472708Swollman}
16482708Swollman
16492708Swollman#endif /* defined STD_INSPIRED */
16502708Swollman
16512708Swollman#ifdef CMUCS
16522708Swollman
16532708Swollman/*
16542708Swollman** The following is supplied for compatibility with
16552708Swollman** previous versions of the CMUCS runtime library.
16562708Swollman*/
16572708Swollman
16582708Swollmanlong
16592708Swollmangtime(tmp)
16602708Swollmanstruct tm * const	tmp;
16612708Swollman{
16622708Swollman	const time_t	t = mktime(tmp);
16632708Swollman
16642708Swollman	if (t == WRONG)
16652708Swollman		return -1;
16662708Swollman	return t;
16672708Swollman}
16682708Swollman
16692708Swollman#endif /* defined CMUCS */
16702708Swollman
16712708Swollman/*
16722708Swollman** XXX--is the below the right way to conditionalize??
16732708Swollman*/
16742708Swollman
16752708Swollman#ifdef STD_INSPIRED
16762708Swollman
16772708Swollman/*
16782708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
16792708Swollman** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
16802708Swollman** is not the case if we are accounting for leap seconds.
16812708Swollman** So, we provide the following conversion routines for use
16822708Swollman** when exchanging timestamps with POSIX conforming systems.
16832708Swollman*/
16842708Swollman
16852708Swollmanstatic long
16862708Swollmanleapcorr(timep)
16872708Swollmantime_t *	timep;
16882708Swollman{
16892708Swollman	register struct state *		sp;
16902708Swollman	register struct lsinfo *	lp;
16912708Swollman	register int			i;
16922708Swollman
16932708Swollman	sp = lclptr;
16942708Swollman	i = sp->leapcnt;
16952708Swollman	while (--i >= 0) {
16962708Swollman		lp = &sp->lsis[i];
16972708Swollman		if (*timep >= lp->ls_trans)
16982708Swollman			return lp->ls_corr;
16992708Swollman	}
17002708Swollman	return 0;
17012708Swollman}
17022708Swollman
17032708Swollmantime_t
17042708Swollmantime2posix(t)
17052708Swollmantime_t	t;
17062708Swollman{
17079936Swollman	tzset();
17082708Swollman	return t - leapcorr(&t);
17092708Swollman}
17102708Swollman
17112708Swollmantime_t
17122708Swollmanposix2time(t)
17132708Swollmantime_t	t;
17142708Swollman{
17152708Swollman	time_t	x;
17162708Swollman	time_t	y;
17172708Swollman
17189936Swollman	tzset();
17192708Swollman	/*
17202708Swollman	** For a positive leap second hit, the result
17212708Swollman	** is not unique.  For a negative leap second
17222708Swollman	** hit, the corresponding time doesn't exist,
17232708Swollman	** so we return an adjacent second.
17242708Swollman	*/
17252708Swollman	x = t + leapcorr(&t);
17262708Swollman	y = x - leapcorr(&x);
17272708Swollman	if (y < t) {
17282708Swollman		do {
17292708Swollman			x++;
17302708Swollman			y = x - leapcorr(&x);
17312708Swollman		} while (y < t);
17322708Swollman		if (t != y)
17332708Swollman			return x - 1;
17342708Swollman	} else if (y > t) {
17352708Swollman		do {
17362708Swollman			--x;
17372708Swollman			y = x - leapcorr(&x);
17382708Swollman		} while (y > t);
17392708Swollman		if (t != y)
17402708Swollman			return x + 1;
17412708Swollman	}
17422708Swollman	return x;
17432708Swollman}
17442708Swollman
17452708Swollman#endif /* defined STD_INSPIRED */
1746