localtime.c revision 13545
12708Swollman#ifndef lint
22708Swollman#ifndef NOID
39936Swollmanstatic char	elsieid[] = "@(#)localtime.c	7.44";
42708Swollman#endif /* !defined NOID */
52708Swollman#endif /* !defined lint */
62708Swollman
72708Swollman/*
82708Swollman** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
92708Swollman** POSIX-style TZ environment variable handling from Guy Harris
102708Swollman** (guy@auspex.com).
112708Swollman*/
122708Swollman
132708Swollman/*LINTLIBRARY*/
142708Swollman
152708Swollman#include "private.h"
162708Swollman#include "tzfile.h"
172708Swollman#include "fcntl.h"
1813545Sjulian#ifdef	_THREAD_SAFE
1913545Sjulian#include <pthread.h>
2013545Sjulian#include "pthread_private.h"
2113545Sjulian#endif
222708Swollman
239936Swollman/*
249936Swollman** SunOS 4.1.1 headers lack O_BINARY.
259936Swollman*/
262708Swollman
272708Swollman#ifdef O_BINARY
282708Swollman#define OPEN_MODE	(O_RDONLY | O_BINARY)
292708Swollman#endif /* defined O_BINARY */
302708Swollman#ifndef O_BINARY
312708Swollman#define OPEN_MODE	O_RDONLY
322708Swollman#endif /* !defined O_BINARY */
332708Swollman
342708Swollman#ifndef WILDABBR
352708Swollman/*
362708Swollman** Someone might make incorrect use of a time zone abbreviation:
372708Swollman**	1.	They might reference tzname[0] before calling tzset (explicitly
389936Swollman**		or implicitly).
392708Swollman**	2.	They might reference tzname[1] before calling tzset (explicitly
409936Swollman**		or implicitly).
412708Swollman**	3.	They might reference tzname[1] after setting to a time zone
422708Swollman**		in which Daylight Saving Time is never observed.
432708Swollman**	4.	They might reference tzname[0] after setting to a time zone
442708Swollman**		in which Standard Time is never observed.
452708Swollman**	5.	They might reference tm.TM_ZONE after calling offtime.
462708Swollman** What's best to do in the above cases is open to debate;
472708Swollman** for now, we just set things up so that in any of the five cases
482708Swollman** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
492708Swollman** string "tzname[0] used before set", and similarly for the other cases.
502708Swollman** And another:  initialize tzname[0] to "ERA", with an explanation in the
512708Swollman** manual page of what this "time zone abbreviation" means (doing this so
522708Swollman** that tzname[0] has the "normal" length of three characters).
532708Swollman*/
542708Swollman#define WILDABBR	"   "
552708Swollman#endif /* !defined WILDABBR */
562708Swollman
579936Swollmanstatic char		wildabbr[] = "WILDABBR";
582708Swollman
599936Swollmanstatic const char	gmt[] = "GMT";
609936Swollman
612708Swollmanstruct ttinfo {				/* time type information */
622708Swollman	long		tt_gmtoff;	/* GMT offset in seconds */
632708Swollman	int		tt_isdst;	/* used to set tm_isdst */
642708Swollman	int		tt_abbrind;	/* abbreviation list index */
652708Swollman	int		tt_ttisstd;	/* TRUE if transition is std time */
669936Swollman	int		tt_ttisgmt;	/* TRUE if transition is GMT */
672708Swollman};
682708Swollman
692708Swollmanstruct lsinfo {				/* leap second information */
702708Swollman	time_t		ls_trans;	/* transition time */
712708Swollman	long		ls_corr;	/* correction to apply */
722708Swollman};
732708Swollman
742708Swollman#define BIGGEST(a, b)	(((a) > (b)) ? (a) : (b))
752708Swollman
762708Swollman#ifdef TZNAME_MAX
772708Swollman#define MY_TZNAME_MAX	TZNAME_MAX
782708Swollman#endif /* defined TZNAME_MAX */
792708Swollman#ifndef TZNAME_MAX
802708Swollman#define MY_TZNAME_MAX	255
812708Swollman#endif /* !defined TZNAME_MAX */
822708Swollman
832708Swollmanstruct state {
842708Swollman	int		leapcnt;
852708Swollman	int		timecnt;
862708Swollman	int		typecnt;
872708Swollman	int		charcnt;
882708Swollman	time_t		ats[TZ_MAX_TIMES];
892708Swollman	unsigned char	types[TZ_MAX_TIMES];
902708Swollman	struct ttinfo	ttis[TZ_MAX_TYPES];
919936Swollman	char		chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
922708Swollman				(2 * (MY_TZNAME_MAX + 1)))];
932708Swollman	struct lsinfo	lsis[TZ_MAX_LEAPS];
942708Swollman};
952708Swollman
962708Swollmanstruct rule {
972708Swollman	int		r_type;		/* type of rule--see below */
982708Swollman	int		r_day;		/* day number of rule */
992708Swollman	int		r_week;		/* week number of rule */
1002708Swollman	int		r_mon;		/* month number of rule */
1012708Swollman	long		r_time;		/* transition time of rule */
1022708Swollman};
1032708Swollman
1042708Swollman#define JULIAN_DAY		0	/* Jn - Julian day */
1052708Swollman#define DAY_OF_YEAR		1	/* n - day of year */
1062708Swollman#define MONTH_NTH_DAY_OF_WEEK	2	/* Mm.n.d - month, week, day of week */
1072708Swollman
1082708Swollman/*
1092708Swollman** Prototypes for static functions.
1102708Swollman*/
1112708Swollman
1122708Swollmanstatic long		detzcode P((const char * codep));
1132708Swollmanstatic const char *	getzname P((const char * strp));
1142708Swollmanstatic const char *	getnum P((const char * strp, int * nump, int min,
1152708Swollman				int max));
1162708Swollmanstatic const char *	getsecs P((const char * strp, long * secsp));
1172708Swollmanstatic const char *	getoffset P((const char * strp, long * offsetp));
1182708Swollmanstatic const char *	getrule P((const char * strp, struct rule * rulep));
1192708Swollmanstatic void		gmtload P((struct state * sp));
1202708Swollmanstatic void		gmtsub P((const time_t * timep, long offset,
1212708Swollman				struct tm * tmp));
1222708Swollmanstatic void		localsub P((const time_t * timep, long offset,
1232708Swollman				struct tm * tmp));
1242708Swollmanstatic int		increment_overflow P((int * number, int delta));
1252708Swollmanstatic int		normalize_overflow P((int * tensptr, int * unitsptr,
1262708Swollman				int base));
1272708Swollmanstatic void		settzname P((void));
1289936Swollmanstatic time_t		time1 P((struct tm * tmp,
1299936Swollman				void(*funcp) P((const time_t *,
1309936Swollman				long, struct tm *)),
1312708Swollman				long offset));
1329936Swollmanstatic time_t		time2 P((struct tm *tmp,
1339936Swollman				void(*funcp) P((const time_t *,
1349936Swollman				long, struct tm*)),
1352708Swollman				long offset, int * okayp));
1362708Swollmanstatic void		timesub P((const time_t * timep, long offset,
1372708Swollman				const struct state * sp, struct tm * tmp));
1382708Swollmanstatic int		tmcomp P((const struct tm * atmp,
1392708Swollman				const struct tm * btmp));
1402708Swollmanstatic time_t		transtime P((time_t janfirst, int year,
1412708Swollman				const struct rule * rulep, long offset));
1422708Swollmanstatic int		tzload P((const char * name, struct state * sp));
1432708Swollmanstatic int		tzparse P((const char * name, struct state * sp,
1442708Swollman				int lastditch));
1452708Swollman
1462708Swollman#ifdef ALL_STATE
1472708Swollmanstatic struct state *	lclptr;
1482708Swollmanstatic struct state *	gmtptr;
1492708Swollman#endif /* defined ALL_STATE */
1502708Swollman
1512708Swollman#ifndef ALL_STATE
1522708Swollmanstatic struct state	lclmem;
1532708Swollmanstatic struct state	gmtmem;
1542708Swollman#define lclptr		(&lclmem)
1552708Swollman#define gmtptr		(&gmtmem)
1562708Swollman#endif /* State Farm */
1572708Swollman
1589936Swollman#ifndef TZ_STRLEN_MAX
1599936Swollman#define TZ_STRLEN_MAX 255
1609936Swollman#endif /* !defined TZ_STRLEN_MAX */
1619936Swollman
1629936Swollmanstatic char		lcl_TZname[TZ_STRLEN_MAX + 1];
1632708Swollmanstatic int		lcl_is_set;
1642708Swollmanstatic int		gmt_is_set;
16513545Sjulian#ifdef	_THREAD_SAFE
16613545Sjulianstatic pthread_mutex_t  lcl_mutex   = PTHREAD_MUTEX_INITIALIZER;
16713545Sjulianstatic pthread_mutex_t  gmt_mutex   = PTHREAD_MUTEX_INITIALIZER;
16813545Sjulian#endif
1692708Swollman
1702708Swollmanchar *			tzname[2] = {
1719936Swollman	wildabbr,
1729936Swollman	wildabbr
1732708Swollman};
1742708Swollman
1759936Swollman/*
1769936Swollman** Section 4.12.3 of X3.159-1989 requires that
1779936Swollman**	Except for the strftime function, these functions [asctime,
1789936Swollman**	ctime, gmtime, localtime] return values in one of two static
1799936Swollman**	objects: a broken-down time structure and an array of char.
1809936Swollman** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
1819936Swollman*/
1829936Swollman
1839936Swollmanstatic struct tm	tm;
1849936Swollman
1852708Swollman#ifdef USG_COMPAT
1862708Swollmantime_t			timezone = 0;
1872708Swollmanint			daylight = 0;
1882708Swollman#endif /* defined USG_COMPAT */
1892708Swollman
1902708Swollman#ifdef ALTZONE
1912708Swollmantime_t			altzone = 0;
1922708Swollman#endif /* defined ALTZONE */
1932708Swollman
1942708Swollmanstatic long
1952708Swollmandetzcode(codep)
1962708Swollmanconst char * const	codep;
1972708Swollman{
1982708Swollman	register long	result;
1992708Swollman	register int	i;
2002708Swollman
2019936Swollman 	result = (codep[0] & 0x80) ? ~0L : 0L;
2022708Swollman	for (i = 0; i < 4; ++i)
2032708Swollman		result = (result << 8) | (codep[i] & 0xff);
2042708Swollman	return result;
2052708Swollman}
2062708Swollman
2072708Swollmanstatic void
2089936Swollmansettzname P((void))
2092708Swollman{
2109936Swollman	register struct state * const		sp = lclptr;
2112708Swollman	register int				i;
2122708Swollman
2139936Swollman	tzname[0] = wildabbr;
2149936Swollman	tzname[1] = wildabbr;
2152708Swollman#ifdef USG_COMPAT
2162708Swollman	daylight = 0;
2172708Swollman	timezone = 0;
2182708Swollman#endif /* defined USG_COMPAT */
2192708Swollman#ifdef ALTZONE
2202708Swollman	altzone = 0;
2212708Swollman#endif /* defined ALTZONE */
2222708Swollman#ifdef ALL_STATE
2232708Swollman	if (sp == NULL) {
2249936Swollman		tzname[0] = tzname[1] = gmt;
2252708Swollman		return;
2262708Swollman	}
2272708Swollman#endif /* defined ALL_STATE */
2282708Swollman	for (i = 0; i < sp->typecnt; ++i) {
2292708Swollman		register const struct ttinfo * const	ttisp = &sp->ttis[i];
2302708Swollman
2312708Swollman		tzname[ttisp->tt_isdst] =
2329936Swollman			&sp->chars[ttisp->tt_abbrind];
2332708Swollman#ifdef USG_COMPAT
2342708Swollman		if (ttisp->tt_isdst)
2352708Swollman			daylight = 1;
2362708Swollman		if (i == 0 || !ttisp->tt_isdst)
2372708Swollman			timezone = -(ttisp->tt_gmtoff);
2382708Swollman#endif /* defined USG_COMPAT */
2392708Swollman#ifdef ALTZONE
2402708Swollman		if (i == 0 || ttisp->tt_isdst)
2412708Swollman			altzone = -(ttisp->tt_gmtoff);
2422708Swollman#endif /* defined ALTZONE */
2432708Swollman	}
2442708Swollman	/*
2452708Swollman	** And to get the latest zone names into tzname. . .
2462708Swollman	*/
2472708Swollman	for (i = 0; i < sp->timecnt; ++i) {
2482708Swollman		register const struct ttinfo * const	ttisp =
2492708Swollman							&sp->ttis[
2502708Swollman								sp->types[i]];
2512708Swollman
2522708Swollman		tzname[ttisp->tt_isdst] =
2539936Swollman			&sp->chars[ttisp->tt_abbrind];
2542708Swollman	}
2552708Swollman}
2562708Swollman
2572708Swollmanstatic int
2582708Swollmantzload(name, sp)
2592708Swollmanregister const char *		name;
2602708Swollmanregister struct state * const	sp;
2612708Swollman{
2622708Swollman	register const char *	p;
2632708Swollman	register int		i;
2642708Swollman	register int		fid;
2652708Swollman
2662708Swollman	if (name == NULL && (name = TZDEFAULT) == NULL)
2672708Swollman		return -1;
2682708Swollman	{
2699936Swollman		register int	doaccess;
2709936Swollman		/*
2719936Swollman		** Section 4.9.1 of the C standard says that
2729936Swollman		** "FILENAME_MAX expands to an integral constant expression
2739936Swollman		** that is the sie needed for an array of char large enough
2749936Swollman		** to hold the longest file name string that the implementation
2759936Swollman		** guarantees can be opened."
2769936Swollman		*/
2772708Swollman		char		fullname[FILENAME_MAX + 1];
2782708Swollman
2792708Swollman		if (name[0] == ':')
2802708Swollman			++name;
2812708Swollman		doaccess = name[0] == '/';
2822708Swollman		if (!doaccess) {
2832708Swollman			if ((p = TZDIR) == NULL)
2842708Swollman				return -1;
2852708Swollman			if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
2862708Swollman				return -1;
2872708Swollman			(void) strcpy(fullname, p);
2882708Swollman			(void) strcat(fullname, "/");
2892708Swollman			(void) strcat(fullname, name);
2902708Swollman			/*
2912708Swollman			** Set doaccess if '.' (as in "../") shows up in name.
2922708Swollman			*/
2932708Swollman			if (strchr(name, '.') != NULL)
2942708Swollman				doaccess = TRUE;
2952708Swollman			name = fullname;
2962708Swollman		}
2979936Swollman		if (doaccess && access(name, R_OK) != 0)
2982708Swollman			return -1;
2992708Swollman		if ((fid = open(name, OPEN_MODE)) == -1)
3002708Swollman			return -1;
3012708Swollman	}
3022708Swollman	{
3039936Swollman		struct tzhead *	tzhp;
3049936Swollman		char		buf[sizeof *sp + sizeof *tzhp];
3059936Swollman		int		ttisstdcnt;
3069936Swollman		int		ttisgmtcnt;
3072708Swollman
3082708Swollman		i = read(fid, buf, sizeof buf);
3099936Swollman		if (close(fid) != 0)
3102708Swollman			return -1;
3119936Swollman		p = buf;
3129936Swollman		p += sizeof tzhp->tzh_reserved;
3139936Swollman		ttisstdcnt = (int) detzcode(p);
3149936Swollman		p += 4;
3159936Swollman		ttisgmtcnt = (int) detzcode(p);
3169936Swollman		p += 4;
3179936Swollman		sp->leapcnt = (int) detzcode(p);
3189936Swollman		p += 4;
3199936Swollman		sp->timecnt = (int) detzcode(p);
3209936Swollman		p += 4;
3219936Swollman		sp->typecnt = (int) detzcode(p);
3229936Swollman		p += 4;
3239936Swollman		sp->charcnt = (int) detzcode(p);
3249936Swollman		p += 4;
3252708Swollman		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
3262708Swollman			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
3272708Swollman			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
3282708Swollman			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
3299936Swollman			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
3309936Swollman			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
3312708Swollman				return -1;
3329936Swollman		if (i - (p - buf) < sp->timecnt * 4 +	/* ats */
3339936Swollman			sp->timecnt +			/* types */
3349936Swollman			sp->typecnt * (4 + 2) +		/* ttinfos */
3359936Swollman			sp->charcnt +			/* chars */
3369936Swollman			sp->leapcnt * (4 + 4) +		/* lsinfos */
3379936Swollman			ttisstdcnt +			/* ttisstds */
3389936Swollman			ttisgmtcnt)			/* ttisgmts */
3392708Swollman				return -1;
3402708Swollman		for (i = 0; i < sp->timecnt; ++i) {
3412708Swollman			sp->ats[i] = detzcode(p);
3422708Swollman			p += 4;
3432708Swollman		}
3442708Swollman		for (i = 0; i < sp->timecnt; ++i) {
3452708Swollman			sp->types[i] = (unsigned char) *p++;
3462708Swollman			if (sp->types[i] >= sp->typecnt)
3472708Swollman				return -1;
3482708Swollman		}
3492708Swollman		for (i = 0; i < sp->typecnt; ++i) {
3502708Swollman			register struct ttinfo *	ttisp;
3512708Swollman
3522708Swollman			ttisp = &sp->ttis[i];
3532708Swollman			ttisp->tt_gmtoff = detzcode(p);
3542708Swollman			p += 4;
3552708Swollman			ttisp->tt_isdst = (unsigned char) *p++;
3562708Swollman			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
3572708Swollman				return -1;
3582708Swollman			ttisp->tt_abbrind = (unsigned char) *p++;
3592708Swollman			if (ttisp->tt_abbrind < 0 ||
3602708Swollman				ttisp->tt_abbrind > sp->charcnt)
3612708Swollman					return -1;
3622708Swollman		}
3632708Swollman		for (i = 0; i < sp->charcnt; ++i)
3642708Swollman			sp->chars[i] = *p++;
3652708Swollman		sp->chars[i] = '\0';	/* ensure '\0' at end */
3662708Swollman		for (i = 0; i < sp->leapcnt; ++i) {
3672708Swollman			register struct lsinfo *	lsisp;
3682708Swollman
3692708Swollman			lsisp = &sp->lsis[i];
3702708Swollman			lsisp->ls_trans = detzcode(p);
3712708Swollman			p += 4;
3722708Swollman			lsisp->ls_corr = detzcode(p);
3732708Swollman			p += 4;
3742708Swollman		}
3752708Swollman		for (i = 0; i < sp->typecnt; ++i) {
3762708Swollman			register struct ttinfo *	ttisp;
3772708Swollman
3782708Swollman			ttisp = &sp->ttis[i];
3792708Swollman			if (ttisstdcnt == 0)
3802708Swollman				ttisp->tt_ttisstd = FALSE;
3812708Swollman			else {
3822708Swollman				ttisp->tt_ttisstd = *p++;
3832708Swollman				if (ttisp->tt_ttisstd != TRUE &&
3842708Swollman					ttisp->tt_ttisstd != FALSE)
3852708Swollman						return -1;
3862708Swollman			}
3872708Swollman		}
3889936Swollman		for (i = 0; i < sp->typecnt; ++i) {
3899936Swollman			register struct ttinfo *	ttisp;
3909936Swollman
3919936Swollman			ttisp = &sp->ttis[i];
3929936Swollman			if (ttisgmtcnt == 0)
3939936Swollman				ttisp->tt_ttisgmt = FALSE;
3949936Swollman			else {
3959936Swollman				ttisp->tt_ttisgmt = *p++;
3969936Swollman				if (ttisp->tt_ttisgmt != TRUE &&
3979936Swollman					ttisp->tt_ttisgmt != FALSE)
3989936Swollman						return -1;
3999936Swollman			}
4009936Swollman		}
4012708Swollman	}
4022708Swollman	return 0;
4032708Swollman}
4042708Swollman
4052708Swollmanstatic const int	mon_lengths[2][MONSPERYEAR] = {
4062708Swollman	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
4072708Swollman	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
4082708Swollman};
4092708Swollman
4102708Swollmanstatic const int	year_lengths[2] = {
4112708Swollman	DAYSPERNYEAR, DAYSPERLYEAR
4122708Swollman};
4132708Swollman
4142708Swollman/*
4152708Swollman** Given a pointer into a time zone string, scan until a character that is not
4162708Swollman** a valid character in a zone name is found.  Return a pointer to that
4172708Swollman** character.
4182708Swollman*/
4192708Swollman
4202708Swollmanstatic const char *
4212708Swollmangetzname(strp)
4222708Swollmanregister const char *	strp;
4232708Swollman{
4242708Swollman	register char	c;
4252708Swollman
4262708Swollman	while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
4272708Swollman		c != '+')
4282708Swollman			++strp;
4292708Swollman	return strp;
4302708Swollman}
4312708Swollman
4322708Swollman/*
4332708Swollman** Given a pointer into a time zone string, extract a number from that string.
4342708Swollman** Check that the number is within a specified range; if it is not, return
4352708Swollman** NULL.
4362708Swollman** Otherwise, return a pointer to the first character not part of the number.
4372708Swollman*/
4382708Swollman
4392708Swollmanstatic const char *
4402708Swollmangetnum(strp, nump, min, max)
4412708Swollmanregister const char *	strp;
4422708Swollmanint * const		nump;
4432708Swollmanconst int		min;
4442708Swollmanconst int		max;
4452708Swollman{
4462708Swollman	register char	c;
4472708Swollman	register int	num;
4482708Swollman
4492708Swollman	if (strp == NULL || !isdigit(*strp))
4502708Swollman		return NULL;
4512708Swollman	num = 0;
4522708Swollman	while ((c = *strp) != '\0' && isdigit(c)) {
4532708Swollman		num = num * 10 + (c - '0');
4542708Swollman		if (num > max)
4552708Swollman			return NULL;	/* illegal value */
4562708Swollman		++strp;
4572708Swollman	}
4582708Swollman	if (num < min)
4592708Swollman		return NULL;		/* illegal value */
4602708Swollman	*nump = num;
4612708Swollman	return strp;
4622708Swollman}
4632708Swollman
4642708Swollman/*
4652708Swollman** Given a pointer into a time zone string, extract a number of seconds,
4662708Swollman** in hh[:mm[:ss]] form, from the string.
4672708Swollman** If any error occurs, return NULL.
4682708Swollman** Otherwise, return a pointer to the first character not part of the number
4692708Swollman** of seconds.
4702708Swollman*/
4712708Swollman
4722708Swollmanstatic const char *
4732708Swollmangetsecs(strp, secsp)
4742708Swollmanregister const char *	strp;
4752708Swollmanlong * const		secsp;
4762708Swollman{
4772708Swollman	int	num;
4782708Swollman
4799936Swollman	/*
4809936Swollman	** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
4819936Swollman	** "M10.4.6/26", which does not conform to Posix,
4829936Swollman	** but which specifies the equivalent of
4839936Swollman	** ``02:00 on the first Sunday on or after 23 Oct''.
4849936Swollman	*/
4859936Swollman	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
4862708Swollman	if (strp == NULL)
4872708Swollman		return NULL;
4889936Swollman	*secsp = num * (long) SECSPERHOUR;
4892708Swollman	if (*strp == ':') {
4902708Swollman		++strp;
4912708Swollman		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
4922708Swollman		if (strp == NULL)
4932708Swollman			return NULL;
4942708Swollman		*secsp += num * SECSPERMIN;
4952708Swollman		if (*strp == ':') {
4962708Swollman			++strp;
4979936Swollman			/* `SECSPERMIN' allows for leap seconds.  */
4989936Swollman			strp = getnum(strp, &num, 0, SECSPERMIN);
4992708Swollman			if (strp == NULL)
5002708Swollman				return NULL;
5012708Swollman			*secsp += num;
5022708Swollman		}
5032708Swollman	}
5042708Swollman	return strp;
5052708Swollman}
5062708Swollman
5072708Swollman/*
5082708Swollman** Given a pointer into a time zone string, extract an offset, in
5092708Swollman** [+-]hh[:mm[:ss]] form, from the string.
5102708Swollman** If any error occurs, return NULL.
5112708Swollman** Otherwise, return a pointer to the first character not part of the time.
5122708Swollman*/
5132708Swollman
5142708Swollmanstatic const char *
5152708Swollmangetoffset(strp, offsetp)
5162708Swollmanregister const char *	strp;
5172708Swollmanlong * const		offsetp;
5182708Swollman{
5192708Swollman	register int	neg;
5202708Swollman
5212708Swollman	if (*strp == '-') {
5222708Swollman		neg = 1;
5232708Swollman		++strp;
5242708Swollman	} else if (isdigit(*strp) || *strp++ == '+')
5252708Swollman		neg = 0;
5262708Swollman	else	return NULL;		/* illegal offset */
5272708Swollman	strp = getsecs(strp, offsetp);
5282708Swollman	if (strp == NULL)
5292708Swollman		return NULL;		/* illegal time */
5302708Swollman	if (neg)
5312708Swollman		*offsetp = -*offsetp;
5322708Swollman	return strp;
5332708Swollman}
5342708Swollman
5352708Swollman/*
5362708Swollman** Given a pointer into a time zone string, extract a rule in the form
5372708Swollman** date[/time].  See POSIX section 8 for the format of "date" and "time".
5382708Swollman** If a valid rule is not found, return NULL.
5392708Swollman** Otherwise, return a pointer to the first character not part of the rule.
5402708Swollman*/
5412708Swollman
5422708Swollmanstatic const char *
5432708Swollmangetrule(strp, rulep)
5442708Swollmanconst char *			strp;
5452708Swollmanregister struct rule * const	rulep;
5462708Swollman{
5472708Swollman	if (*strp == 'J') {
5482708Swollman		/*
5492708Swollman		** Julian day.
5502708Swollman		*/
5512708Swollman		rulep->r_type = JULIAN_DAY;
5522708Swollman		++strp;
5532708Swollman		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
5542708Swollman	} else if (*strp == 'M') {
5552708Swollman		/*
5562708Swollman		** Month, week, day.
5572708Swollman		*/
5582708Swollman		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
5592708Swollman		++strp;
5602708Swollman		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
5612708Swollman		if (strp == NULL)
5622708Swollman			return NULL;
5632708Swollman		if (*strp++ != '.')
5642708Swollman			return NULL;
5652708Swollman		strp = getnum(strp, &rulep->r_week, 1, 5);
5662708Swollman		if (strp == NULL)
5672708Swollman			return NULL;
5682708Swollman		if (*strp++ != '.')
5692708Swollman			return NULL;
5702708Swollman		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
5712708Swollman	} else if (isdigit(*strp)) {
5722708Swollman		/*
5732708Swollman		** Day of year.
5742708Swollman		*/
5752708Swollman		rulep->r_type = DAY_OF_YEAR;
5762708Swollman		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
5772708Swollman	} else	return NULL;		/* invalid format */
5782708Swollman	if (strp == NULL)
5792708Swollman		return NULL;
5802708Swollman	if (*strp == '/') {
5812708Swollman		/*
5822708Swollman		** Time specified.
5832708Swollman		*/
5842708Swollman		++strp;
5852708Swollman		strp = getsecs(strp, &rulep->r_time);
5862708Swollman	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
5872708Swollman	return strp;
5882708Swollman}
5892708Swollman
5902708Swollman/*
5912708Swollman** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
5922708Swollman** year, a rule, and the offset from GMT at the time that rule takes effect,
5932708Swollman** calculate the Epoch-relative time that rule takes effect.
5942708Swollman*/
5952708Swollman
5962708Swollmanstatic time_t
5972708Swollmantranstime(janfirst, year, rulep, offset)
5982708Swollmanconst time_t				janfirst;
5992708Swollmanconst int				year;
6002708Swollmanregister const struct rule * const	rulep;
6012708Swollmanconst long				offset;
6022708Swollman{
6032708Swollman	register int	leapyear;
6042708Swollman	register time_t	value;
6052708Swollman	register int	i;
6062708Swollman	int		d, m1, yy0, yy1, yy2, dow;
6072708Swollman
6089936Swollman	INITIALIZE(value);
6092708Swollman	leapyear = isleap(year);
6102708Swollman	switch (rulep->r_type) {
6112708Swollman
6122708Swollman	case JULIAN_DAY:
6132708Swollman		/*
6142708Swollman		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
6152708Swollman		** years.
6162708Swollman		** In non-leap years, or if the day number is 59 or less, just
6172708Swollman		** add SECSPERDAY times the day number-1 to the time of
6182708Swollman		** January 1, midnight, to get the day.
6192708Swollman		*/
6202708Swollman		value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
6212708Swollman		if (leapyear && rulep->r_day >= 60)
6222708Swollman			value += SECSPERDAY;
6232708Swollman		break;
6242708Swollman
6252708Swollman	case DAY_OF_YEAR:
6262708Swollman		/*
6272708Swollman		** n - day of year.
6282708Swollman		** Just add SECSPERDAY times the day number to the time of
6292708Swollman		** January 1, midnight, to get the day.
6302708Swollman		*/
6312708Swollman		value = janfirst + rulep->r_day * SECSPERDAY;
6322708Swollman		break;
6332708Swollman
6342708Swollman	case MONTH_NTH_DAY_OF_WEEK:
6352708Swollman		/*
6362708Swollman		** Mm.n.d - nth "dth day" of month m.
6372708Swollman		*/
6382708Swollman		value = janfirst;
6392708Swollman		for (i = 0; i < rulep->r_mon - 1; ++i)
6402708Swollman			value += mon_lengths[leapyear][i] * SECSPERDAY;
6412708Swollman
6422708Swollman		/*
6432708Swollman		** Use Zeller's Congruence to get day-of-week of first day of
6442708Swollman		** month.
6452708Swollman		*/
6462708Swollman		m1 = (rulep->r_mon + 9) % 12 + 1;
6472708Swollman		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
6482708Swollman		yy1 = yy0 / 100;
6492708Swollman		yy2 = yy0 % 100;
6502708Swollman		dow = ((26 * m1 - 2) / 10 +
6512708Swollman			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
6522708Swollman		if (dow < 0)
6532708Swollman			dow += DAYSPERWEEK;
6542708Swollman
6552708Swollman		/*
6562708Swollman		** "dow" is the day-of-week of the first day of the month.  Get
6572708Swollman		** the day-of-month (zero-origin) of the first "dow" day of the
6582708Swollman		** month.
6592708Swollman		*/
6602708Swollman		d = rulep->r_day - dow;
6612708Swollman		if (d < 0)
6622708Swollman			d += DAYSPERWEEK;
6632708Swollman		for (i = 1; i < rulep->r_week; ++i) {
6642708Swollman			if (d + DAYSPERWEEK >=
6652708Swollman				mon_lengths[leapyear][rulep->r_mon - 1])
6662708Swollman					break;
6672708Swollman			d += DAYSPERWEEK;
6682708Swollman		}
6692708Swollman
6702708Swollman		/*
6712708Swollman		** "d" is the day-of-month (zero-origin) of the day we want.
6722708Swollman		*/
6732708Swollman		value += d * SECSPERDAY;
6742708Swollman		break;
6752708Swollman	}
6762708Swollman
6772708Swollman	/*
6782708Swollman	** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
6792708Swollman	** question.  To get the Epoch-relative time of the specified local
6802708Swollman	** time on that day, add the transition time and the current offset
6812708Swollman	** from GMT.
6822708Swollman	*/
6832708Swollman	return value + rulep->r_time + offset;
6842708Swollman}
6852708Swollman
6862708Swollman/*
6872708Swollman** Given a POSIX section 8-style TZ string, fill in the rule tables as
6882708Swollman** appropriate.
6892708Swollman*/
6902708Swollman
6912708Swollmanstatic int
6922708Swollmantzparse(name, sp, lastditch)
6932708Swollmanconst char *			name;
6942708Swollmanregister struct state * const	sp;
6952708Swollmanconst int			lastditch;
6962708Swollman{
6972708Swollman	const char *			stdname;
6982708Swollman	const char *			dstname;
6999936Swollman	size_t				stdlen;
7009936Swollman	size_t				dstlen;
7012708Swollman	long				stdoffset;
7022708Swollman	long				dstoffset;
7032708Swollman	register time_t *		atp;
7042708Swollman	register unsigned char *	typep;
7052708Swollman	register char *			cp;
7062708Swollman	register int			load_result;
7072708Swollman
7089936Swollman	INITIALIZE(dstname);
7092708Swollman	stdname = name;
7102708Swollman	if (lastditch) {
7112708Swollman		stdlen = strlen(name);	/* length of standard zone name */
7122708Swollman		name += stdlen;
7132708Swollman		if (stdlen >= sizeof sp->chars)
7142708Swollman			stdlen = (sizeof sp->chars) - 1;
7152708Swollman	} else {
7162708Swollman		name = getzname(name);
7172708Swollman		stdlen = name - stdname;
7182708Swollman		if (stdlen < 3)
7192708Swollman			return -1;
7202708Swollman	}
7212708Swollman	if (*name == '\0')
7222708Swollman		return -1;	/* was "stdoffset = 0;" */
7232708Swollman	else {
7242708Swollman		name = getoffset(name, &stdoffset);
7252708Swollman		if (name == NULL)
7262708Swollman			return -1;
7272708Swollman	}
7282708Swollman	load_result = tzload(TZDEFRULES, sp);
7292708Swollman	if (load_result != 0)
7302708Swollman		sp->leapcnt = 0;		/* so, we're off a little */
7312708Swollman	if (*name != '\0') {
7322708Swollman		dstname = name;
7332708Swollman		name = getzname(name);
7342708Swollman		dstlen = name - dstname;	/* length of DST zone name */
7352708Swollman		if (dstlen < 3)
7362708Swollman			return -1;
7372708Swollman		if (*name != '\0' && *name != ',' && *name != ';') {
7382708Swollman			name = getoffset(name, &dstoffset);
7392708Swollman			if (name == NULL)
7402708Swollman				return -1;
7412708Swollman		} else	dstoffset = stdoffset - SECSPERHOUR;
7422708Swollman		if (*name == ',' || *name == ';') {
7432708Swollman			struct rule	start;
7442708Swollman			struct rule	end;
7452708Swollman			register int	year;
7462708Swollman			register time_t	janfirst;
7472708Swollman			time_t		starttime;
7482708Swollman			time_t		endtime;
7492708Swollman
7502708Swollman			++name;
7512708Swollman			if ((name = getrule(name, &start)) == NULL)
7522708Swollman				return -1;
7532708Swollman			if (*name++ != ',')
7542708Swollman				return -1;
7552708Swollman			if ((name = getrule(name, &end)) == NULL)
7562708Swollman				return -1;
7572708Swollman			if (*name != '\0')
7582708Swollman				return -1;
7592708Swollman			sp->typecnt = 2;	/* standard time and DST */
7602708Swollman			/*
7612708Swollman			** Two transitions per year, from EPOCH_YEAR to 2037.
7622708Swollman			*/
7632708Swollman			sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
7642708Swollman			if (sp->timecnt > TZ_MAX_TIMES)
7652708Swollman				return -1;
7662708Swollman			sp->ttis[0].tt_gmtoff = -dstoffset;
7672708Swollman			sp->ttis[0].tt_isdst = 1;
7682708Swollman			sp->ttis[0].tt_abbrind = stdlen + 1;
7692708Swollman			sp->ttis[1].tt_gmtoff = -stdoffset;
7702708Swollman			sp->ttis[1].tt_isdst = 0;
7712708Swollman			sp->ttis[1].tt_abbrind = 0;
7722708Swollman			atp = sp->ats;
7732708Swollman			typep = sp->types;
7742708Swollman			janfirst = 0;
7752708Swollman			for (year = EPOCH_YEAR; year <= 2037; ++year) {
7762708Swollman				starttime = transtime(janfirst, year, &start,
7772708Swollman					stdoffset);
7782708Swollman				endtime = transtime(janfirst, year, &end,
7792708Swollman					dstoffset);
7802708Swollman				if (starttime > endtime) {
7812708Swollman					*atp++ = endtime;
7822708Swollman					*typep++ = 1;	/* DST ends */
7832708Swollman					*atp++ = starttime;
7842708Swollman					*typep++ = 0;	/* DST begins */
7852708Swollman				} else {
7862708Swollman					*atp++ = starttime;
7872708Swollman					*typep++ = 0;	/* DST begins */
7882708Swollman					*atp++ = endtime;
7892708Swollman					*typep++ = 1;	/* DST ends */
7902708Swollman				}
7912708Swollman				janfirst += year_lengths[isleap(year)] *
7922708Swollman					SECSPERDAY;
7932708Swollman			}
7942708Swollman		} else {
7959936Swollman			register long	theirstdoffset;
7969936Swollman			register long	theirdstoffset;
7979936Swollman			register long	theiroffset;
7989936Swollman			register int	isdst;
7992708Swollman			register int	i;
8009936Swollman			register int	j;
8012708Swollman
8022708Swollman			if (*name != '\0')
8032708Swollman				return -1;
8042708Swollman			if (load_result != 0)
8052708Swollman				return -1;
8062708Swollman			/*
8079936Swollman			** Initial values of theirstdoffset and theirdstoffset.
8082708Swollman			*/
8099936Swollman			theirstdoffset = 0;
8109936Swollman			for (i = 0; i < sp->timecnt; ++i) {
8119936Swollman				j = sp->types[i];
8129936Swollman				if (!sp->ttis[j].tt_isdst) {
8139936Swollman					theirstdoffset = -sp->ttis[j].tt_gmtoff;
8149936Swollman					break;
8152708Swollman				}
8162708Swollman			}
8179936Swollman			theirdstoffset = 0;
8189936Swollman			for (i = 0; i < sp->timecnt; ++i) {
8199936Swollman				j = sp->types[i];
8209936Swollman				if (sp->ttis[j].tt_isdst) {
8219936Swollman					theirdstoffset = -sp->ttis[j].tt_gmtoff;
8229936Swollman					break;
8239936Swollman				}
8249936Swollman			}
8252708Swollman			/*
8269936Swollman			** Initially we're assumed to be in standard time.
8272708Swollman			*/
8289936Swollman			isdst = FALSE;
8299936Swollman			theiroffset = theirstdoffset;
8302708Swollman			/*
8319936Swollman			** Now juggle transition times and types
8329936Swollman			** tracking offsets as you do.
8332708Swollman			*/
8342708Swollman			for (i = 0; i < sp->timecnt; ++i) {
8359936Swollman				j = sp->types[i];
8369936Swollman				sp->types[i] = sp->ttis[j].tt_isdst;
8379936Swollman				if (sp->ttis[j].tt_ttisgmt) {
8389936Swollman					/* No adjustment to transition time */
8399936Swollman				} else {
8409936Swollman					/*
8419936Swollman					** If summer time is in effect, and the
8429936Swollman					** transition time was not specified as
8439936Swollman					** standard time, add the summer time
8449936Swollman					** offset to the transition time;
8459936Swollman					** otherwise, add the standard time
8469936Swollman					** offset to the transition time.
8479936Swollman					*/
8489936Swollman					/*
8499936Swollman					** Transitions from DST to DDST
8509936Swollman					** will effectively disappear since
8519936Swollman					** POSIX provides for only one DST
8529936Swollman					** offset.
8539936Swollman					*/
8549936Swollman					if (isdst && !sp->ttis[j].tt_ttisstd) {
8559936Swollman						sp->ats[i] += dstoffset -
8569936Swollman							theirdstoffset;
8579936Swollman					} else {
8589936Swollman						sp->ats[i] += stdoffset -
8599936Swollman							theirstdoffset;
8609936Swollman					}
8619936Swollman				}
8629936Swollman				theiroffset = -sp->ttis[j].tt_gmtoff;
8639936Swollman				if (sp->ttis[j].tt_isdst)
8649936Swollman					theirdstoffset = theiroffset;
8659936Swollman				else	theirstdoffset = theiroffset;
8662708Swollman			}
8679936Swollman			/*
8689936Swollman			** Finally, fill in ttis.
8699936Swollman			** ttisstd and ttisgmt need not be handled.
8709936Swollman			*/
8719936Swollman			sp->ttis[0].tt_gmtoff = -stdoffset;
8729936Swollman			sp->ttis[0].tt_isdst = FALSE;
8739936Swollman			sp->ttis[0].tt_abbrind = 0;
8749936Swollman			sp->ttis[1].tt_gmtoff = -dstoffset;
8759936Swollman			sp->ttis[1].tt_isdst = TRUE;
8769936Swollman			sp->ttis[1].tt_abbrind = stdlen + 1;
8772708Swollman		}
8782708Swollman	} else {
8792708Swollman		dstlen = 0;
8802708Swollman		sp->typecnt = 1;		/* only standard time */
8812708Swollman		sp->timecnt = 0;
8822708Swollman		sp->ttis[0].tt_gmtoff = -stdoffset;
8832708Swollman		sp->ttis[0].tt_isdst = 0;
8842708Swollman		sp->ttis[0].tt_abbrind = 0;
8852708Swollman	}
8862708Swollman	sp->charcnt = stdlen + 1;
8872708Swollman	if (dstlen != 0)
8882708Swollman		sp->charcnt += dstlen + 1;
8892708Swollman	if (sp->charcnt > sizeof sp->chars)
8902708Swollman		return -1;
8912708Swollman	cp = sp->chars;
8922708Swollman	(void) strncpy(cp, stdname, stdlen);
8932708Swollman	cp += stdlen;
8942708Swollman	*cp++ = '\0';
8952708Swollman	if (dstlen != 0) {
8962708Swollman		(void) strncpy(cp, dstname, dstlen);
8972708Swollman		*(cp + dstlen) = '\0';
8982708Swollman	}
8992708Swollman	return 0;
9002708Swollman}
9012708Swollman
9022708Swollmanstatic void
9032708Swollmangmtload(sp)
9042708Swollmanstruct state * const	sp;
9052708Swollman{
9069936Swollman	if (tzload(gmt, sp) != 0)
9079936Swollman		(void) tzparse(gmt, sp, TRUE);
9082708Swollman}
9092708Swollman
9102708Swollman#ifndef STD_INSPIRED
9119936Swollman/*
9129936Swollman** A non-static declaration of tzsetwall in a system header file
9139936Swollman** may cause a warning about this upcoming static declaration...
9149936Swollman*/
9152708Swollmanstatic
9162708Swollman#endif /* !defined STD_INSPIRED */
91713545Sjulian#ifdef	_THREAD_SAFE
9182708Swollmanvoid
91913545Sjuliantzsetwall_basic P((void))
92013545Sjulian#else
92113545Sjulianvoid
9229936Swollmantzsetwall P((void))
92313545Sjulian#endif
9242708Swollman{
9259936Swollman	if (lcl_is_set < 0)
9269936Swollman		return;
9279936Swollman	lcl_is_set = -1;
9289936Swollman
9292708Swollman#ifdef ALL_STATE
9302708Swollman	if (lclptr == NULL) {
9312708Swollman		lclptr = (struct state *) malloc(sizeof *lclptr);
9322708Swollman		if (lclptr == NULL) {
9332708Swollman			settzname();	/* all we can do */
9342708Swollman			return;
9352708Swollman		}
9362708Swollman	}
9372708Swollman#endif /* defined ALL_STATE */
9382708Swollman	if (tzload((char *) NULL, lclptr) != 0)
9392708Swollman		gmtload(lclptr);
9402708Swollman	settzname();
9412708Swollman}
9422708Swollman
94313545Sjulian#ifdef	_THREAD_SAFE
9442708Swollmanvoid
94513545Sjuliantzsetwall P((void))
94613545Sjulian{
94713545Sjulian	pthread_mutex_lock(&lcl_mutex);
94813545Sjulian	tzsetwall_basic();
94913545Sjulian	pthread_mutex_unlock(&lcl_mutex);
95013545Sjulian}
95113545Sjulian#endif
95213545Sjulian
95313545Sjulian#ifdef	_THREAD_SAFE
95413545Sjulianstatic void
95513545Sjuliantzset_basic P((void))
95613545Sjulian#else
95713545Sjulianvoid
9589936Swollmantzset P((void))
95913545Sjulian#endif
9602708Swollman{
9612708Swollman	register const char *	name;
9622708Swollman
9632708Swollman	name = getenv("TZ");
9642708Swollman	if (name == NULL) {
9652708Swollman		tzsetwall();
9662708Swollman		return;
9672708Swollman	}
9689936Swollman
9699936Swollman	if (lcl_is_set > 0  &&  strcmp(lcl_TZname, name) == 0)
9709936Swollman		return;
9719936Swollman	lcl_is_set = (strlen(name) < sizeof(lcl_TZname));
9729936Swollman	if (lcl_is_set)
9739936Swollman		(void) strcpy(lcl_TZname, name);
9749936Swollman
9752708Swollman#ifdef ALL_STATE
9762708Swollman	if (lclptr == NULL) {
9772708Swollman		lclptr = (struct state *) malloc(sizeof *lclptr);
9782708Swollman		if (lclptr == NULL) {
9792708Swollman			settzname();	/* all we can do */
9802708Swollman			return;
9812708Swollman		}
9822708Swollman	}
9832708Swollman#endif /* defined ALL_STATE */
9842708Swollman	if (*name == '\0') {
9852708Swollman		/*
9862708Swollman		** User wants it fast rather than right.
9872708Swollman		*/
9882708Swollman		lclptr->leapcnt = 0;		/* so, we're off a little */
9892708Swollman		lclptr->timecnt = 0;
9902708Swollman		lclptr->ttis[0].tt_gmtoff = 0;
9912708Swollman		lclptr->ttis[0].tt_abbrind = 0;
9929936Swollman		(void) strcpy(lclptr->chars, gmt);
9932708Swollman	} else if (tzload(name, lclptr) != 0)
9942708Swollman		if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
9952708Swollman			(void) gmtload(lclptr);
9962708Swollman	settzname();
9972708Swollman}
9982708Swollman
99913545Sjulian#ifdef	_THREAD_SAFE
100013545Sjulianvoid
100113545Sjuliantzset P((void))
100213545Sjulian{
100313545Sjulian	pthread_mutex_lock(&lcl_mutex);
100413545Sjulian	tzset_basic();
100513545Sjulian	pthread_mutex_unlock(&lcl_mutex);
100613545Sjulian}
100713545Sjulian#endif
100813545Sjulian
10092708Swollman/*
10102708Swollman** The easy way to behave "as if no library function calls" localtime
10112708Swollman** is to not call it--so we drop its guts into "localsub", which can be
10122708Swollman** freely called.  (And no, the PANS doesn't require the above behavior--
10132708Swollman** but it *is* desirable.)
10142708Swollman**
10152708Swollman** The unused offset argument is for the benefit of mktime variants.
10162708Swollman*/
10172708Swollman
10182708Swollman/*ARGSUSED*/
10192708Swollmanstatic void
10202708Swollmanlocalsub(timep, offset, tmp)
10212708Swollmanconst time_t * const	timep;
10222708Swollmanconst long		offset;
10232708Swollmanstruct tm * const	tmp;
10242708Swollman{
10259936Swollman	register struct state *		sp;
10262708Swollman	register const struct ttinfo *	ttisp;
10272708Swollman	register int			i;
10282708Swollman	const time_t			t = *timep;
10292708Swollman
10302708Swollman	sp = lclptr;
10312708Swollman#ifdef ALL_STATE
10322708Swollman	if (sp == NULL) {
10332708Swollman		gmtsub(timep, offset, tmp);
10342708Swollman		return;
10352708Swollman	}
10362708Swollman#endif /* defined ALL_STATE */
10372708Swollman	if (sp->timecnt == 0 || t < sp->ats[0]) {
10382708Swollman		i = 0;
10392708Swollman		while (sp->ttis[i].tt_isdst)
10402708Swollman			if (++i >= sp->typecnt) {
10412708Swollman				i = 0;
10422708Swollman				break;
10432708Swollman			}
10442708Swollman	} else {
10452708Swollman		for (i = 1; i < sp->timecnt; ++i)
10462708Swollman			if (t < sp->ats[i])
10472708Swollman				break;
10482708Swollman		i = sp->types[i - 1];
10492708Swollman	}
10502708Swollman	ttisp = &sp->ttis[i];
10512708Swollman	/*
10522708Swollman	** To get (wrong) behavior that's compatible with System V Release 2.0
10532708Swollman	** you'd replace the statement below with
10542708Swollman	**	t += ttisp->tt_gmtoff;
10552708Swollman	**	timesub(&t, 0L, sp, tmp);
10562708Swollman	*/
10572708Swollman	timesub(&t, ttisp->tt_gmtoff, sp, tmp);
10582708Swollman	tmp->tm_isdst = ttisp->tt_isdst;
10599936Swollman	tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
10602708Swollman#ifdef TM_ZONE
10619936Swollman	tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
10622708Swollman#endif /* defined TM_ZONE */
10632708Swollman}
10642708Swollman
106513545Sjulian#ifdef	_THREAD_SAFE
106613545Sjulianint
106713545Sjulianlocaltime_r(timep, p_tm)
106813545Sjulianconst time_t * const	timep;
106913545Sjulianstruct tm *p_tm;
107013545Sjulian{
107113545Sjulian	pthread_mutex_lock(&lcl_mutex);
107213545Sjulian	tzset();
107313545Sjulian	localsub(timep, 0L, p_tm);
107413545Sjulian	pthread_mutex_unlock(&lcl_mutex);
107513545Sjulian	return(0);
107613545Sjulian}
107713545Sjulian#endif
107813545Sjulian
10792708Swollmanstruct tm *
10802708Swollmanlocaltime(timep)
10812708Swollmanconst time_t * const	timep;
10822708Swollman{
108313545Sjulian#ifdef	_THREAD_SAFE
108413545Sjulian	static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
108513545Sjulian	static pthread_key_t localtime_key = -1;
108613545Sjulian	struct tm *p_tm;
108713545Sjulian
108813545Sjulian	pthread_mutex_lock(&localtime_mutex);
108913545Sjulian	if (localtime_key < 0) {
109013545Sjulian		if (pthread_keycreate(&localtime_key, free) < 0) {
109113545Sjulian			pthread_mutex_unlock(&localtime_mutex);
109213545Sjulian			return(NULL);
109313545Sjulian		}
109413545Sjulian	}
109513545Sjulian	pthread_mutex_unlock(&localtime_mutex);
109613545Sjulian	if (pthread_getspecific(localtime_key,(void **) &p_tm) != 0) {
109713545Sjulian		return(NULL);
109813545Sjulian	} else if (p_tm == NULL) {
109913545Sjulian		if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) {
110013545Sjulian			return(NULL);
110113545Sjulian		}
110213545Sjulian		pthread_setspecific(localtime_key, p_tm);
110313545Sjulian	}
110413545Sjulian	pthread_mutex_lock(&lcl_mutex);
11059936Swollman	tzset();
110613545Sjulian	localsub(timep, 0L, p_tm);
110713545Sjulian	pthread_mutex_unlock(&lcl_mutex);
110813545Sjulian	return p_tm;
110913545Sjulian#else
111013545Sjulian	tzset();
11112708Swollman	localsub(timep, 0L, &tm);
11122708Swollman	return &tm;
111313545Sjulian#endif
11142708Swollman}
11152708Swollman
11162708Swollman/*
11172708Swollman** gmtsub is to gmtime as localsub is to localtime.
11182708Swollman*/
11192708Swollman
11202708Swollmanstatic void
11212708Swollmangmtsub(timep, offset, tmp)
11222708Swollmanconst time_t * const	timep;
11232708Swollmanconst long		offset;
11242708Swollmanstruct tm * const	tmp;
11252708Swollman{
112613545Sjulian#ifdef	_THREAD_SAFE
112713545Sjulian	pthread_mutex_lock(&gmt_mutex);
112813545Sjulian#endif
11292708Swollman	if (!gmt_is_set) {
11302708Swollman		gmt_is_set = TRUE;
11312708Swollman#ifdef ALL_STATE
11322708Swollman		gmtptr = (struct state *) malloc(sizeof *gmtptr);
11332708Swollman		if (gmtptr != NULL)
11342708Swollman#endif /* defined ALL_STATE */
11352708Swollman			gmtload(gmtptr);
11362708Swollman	}
113713545Sjulian#ifdef	_THREAD_SAFE
113813545Sjulian	pthread_mutex_unlock(&gmt_mutex);
113913545Sjulian#endif
11402708Swollman	timesub(timep, offset, gmtptr, tmp);
11412708Swollman#ifdef TM_ZONE
11422708Swollman	/*
11432708Swollman	** Could get fancy here and deliver something such as
11442708Swollman	** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
11452708Swollman	** but this is no time for a treasure hunt.
11462708Swollman	*/
11472708Swollman	if (offset != 0)
11489936Swollman		tmp->TM_ZONE = wildabbr;
11492708Swollman	else {
11502708Swollman#ifdef ALL_STATE
11512708Swollman		if (gmtptr == NULL)
11529936Swollman			tmp->TM_ZONE = gmt;
11532708Swollman		else	tmp->TM_ZONE = gmtptr->chars;
11542708Swollman#endif /* defined ALL_STATE */
11552708Swollman#ifndef ALL_STATE
11562708Swollman		tmp->TM_ZONE = gmtptr->chars;
11572708Swollman#endif /* State Farm */
11582708Swollman	}
11592708Swollman#endif /* defined TM_ZONE */
11602708Swollman}
11612708Swollman
11622708Swollmanstruct tm *
11632708Swollmangmtime(timep)
11642708Swollmanconst time_t * const	timep;
11652708Swollman{
116613545Sjulian#ifdef	_THREAD_SAFE
116713545Sjulian	static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
116813545Sjulian	static pthread_key_t gmtime_key = -1;
116913545Sjulian	struct tm *p_tm;
117013545Sjulian
117113545Sjulian	pthread_mutex_lock(&gmtime_mutex);
117213545Sjulian	if (gmtime_key < 0) {
117313545Sjulian		if (pthread_keycreate(&gmtime_key, free) < 0) {
117413545Sjulian			pthread_mutex_unlock(&gmtime_mutex);
117513545Sjulian			return(NULL);
117613545Sjulian		}
117713545Sjulian	}
117813545Sjulian	pthread_mutex_unlock(&gmtime_mutex);
117913545Sjulian	if (pthread_getspecific(gmtime_key,(void **) &p_tm) != 0) {
118013545Sjulian		return(NULL);
118113545Sjulian	} else if (p_tm == NULL) {
118213545Sjulian		if ((p_tm = (struct tm *)malloc(sizeof(struct tm))) == NULL) {
118313545Sjulian			return(NULL);
118413545Sjulian		}
118513545Sjulian		pthread_setspecific(gmtime_key, p_tm);
118613545Sjulian	}
118713545Sjulian	gmtsub(timep, 0L, p_tm);
118813545Sjulian	return(p_tm);
118913545Sjulian#else
11902708Swollman	gmtsub(timep, 0L, &tm);
11912708Swollman	return &tm;
119213545Sjulian#endif
11932708Swollman}
11942708Swollman
119513545Sjulian#ifdef	_THREAD_SAFE
119613545Sjulianint
119713545Sjuliangmtime_r(const time_t * timep, struct tm * tm)
119813545Sjulian{
119913545Sjulian	gmtsub(timep, 0L, tm);
120013545Sjulian	return(0);
120113545Sjulian}
120213545Sjulian#endif
120313545Sjulian
12042708Swollman#ifdef STD_INSPIRED
12052708Swollman
12062708Swollmanstruct tm *
12072708Swollmanofftime(timep, offset)
12082708Swollmanconst time_t * const	timep;
12092708Swollmanconst long		offset;
12102708Swollman{
12112708Swollman	gmtsub(timep, offset, &tm);
12122708Swollman	return &tm;
12132708Swollman}
12142708Swollman
12152708Swollman#endif /* defined STD_INSPIRED */
12162708Swollman
12172708Swollmanstatic void
12182708Swollmantimesub(timep, offset, sp, tmp)
12192708Swollmanconst time_t * const			timep;
12202708Swollmanconst long				offset;
12212708Swollmanregister const struct state * const	sp;
12222708Swollmanregister struct tm * const		tmp;
12232708Swollman{
12242708Swollman	register const struct lsinfo *	lp;
12252708Swollman	register long			days;
12262708Swollman	register long			rem;
12272708Swollman	register int			y;
12282708Swollman	register int			yleap;
12292708Swollman	register const int *		ip;
12302708Swollman	register long			corr;
12312708Swollman	register int			hit;
12322708Swollman	register int			i;
12332708Swollman
12342708Swollman	corr = 0;
12352708Swollman	hit = 0;
12362708Swollman#ifdef ALL_STATE
12372708Swollman	i = (sp == NULL) ? 0 : sp->leapcnt;
12382708Swollman#endif /* defined ALL_STATE */
12392708Swollman#ifndef ALL_STATE
12402708Swollman	i = sp->leapcnt;
12412708Swollman#endif /* State Farm */
12422708Swollman	while (--i >= 0) {
12432708Swollman		lp = &sp->lsis[i];
12442708Swollman		if (*timep >= lp->ls_trans) {
12452708Swollman			if (*timep == lp->ls_trans) {
12462708Swollman				hit = ((i == 0 && lp->ls_corr > 0) ||
12472708Swollman					lp->ls_corr > sp->lsis[i - 1].ls_corr);
12482708Swollman				if (hit)
12492708Swollman					while (i > 0 &&
12502708Swollman						sp->lsis[i].ls_trans ==
12512708Swollman						sp->lsis[i - 1].ls_trans + 1 &&
12522708Swollman						sp->lsis[i].ls_corr ==
12532708Swollman						sp->lsis[i - 1].ls_corr + 1) {
12542708Swollman							++hit;
12552708Swollman							--i;
12562708Swollman					}
12572708Swollman			}
12582708Swollman			corr = lp->ls_corr;
12592708Swollman			break;
12602708Swollman		}
12612708Swollman	}
12622708Swollman	days = *timep / SECSPERDAY;
12632708Swollman	rem = *timep % SECSPERDAY;
12642708Swollman#ifdef mc68k
12652708Swollman	if (*timep == 0x80000000) {
12662708Swollman		/*
12672708Swollman		** A 3B1 muffs the division on the most negative number.
12682708Swollman		*/
12692708Swollman		days = -24855;
12702708Swollman		rem = -11648;
12712708Swollman	}
12729936Swollman#endif /* defined mc68k */
12732708Swollman	rem += (offset - corr);
12742708Swollman	while (rem < 0) {
12752708Swollman		rem += SECSPERDAY;
12762708Swollman		--days;
12772708Swollman	}
12782708Swollman	while (rem >= SECSPERDAY) {
12792708Swollman		rem -= SECSPERDAY;
12802708Swollman		++days;
12812708Swollman	}
12822708Swollman	tmp->tm_hour = (int) (rem / SECSPERHOUR);
12832708Swollman	rem = rem % SECSPERHOUR;
12842708Swollman	tmp->tm_min = (int) (rem / SECSPERMIN);
12852708Swollman	tmp->tm_sec = (int) (rem % SECSPERMIN);
12862708Swollman	if (hit)
12872708Swollman		/*
12882708Swollman		** A positive leap second requires a special
12892708Swollman		** representation.  This uses "... ??:59:60" et seq.
12902708Swollman		*/
12912708Swollman		tmp->tm_sec += hit;
12922708Swollman	tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
12932708Swollman	if (tmp->tm_wday < 0)
12942708Swollman		tmp->tm_wday += DAYSPERWEEK;
12952708Swollman	y = EPOCH_YEAR;
12962708Swollman	if (days >= 0)
12972708Swollman		for ( ; ; ) {
12982708Swollman			yleap = isleap(y);
12992708Swollman			if (days < (long) year_lengths[yleap])
13002708Swollman				break;
13012708Swollman			++y;
13022708Swollman			days = days - (long) year_lengths[yleap];
13032708Swollman		}
13042708Swollman	else do {
13052708Swollman		--y;
13062708Swollman		yleap = isleap(y);
13072708Swollman		days = days + (long) year_lengths[yleap];
13082708Swollman	} while (days < 0);
13092708Swollman	tmp->tm_year = y - TM_YEAR_BASE;
13102708Swollman	tmp->tm_yday = (int) days;
13112708Swollman	ip = mon_lengths[yleap];
13122708Swollman	for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
13132708Swollman		days = days - (long) ip[tmp->tm_mon];
13142708Swollman	tmp->tm_mday = (int) (days + 1);
13152708Swollman	tmp->tm_isdst = 0;
13162708Swollman#ifdef TM_GMTOFF
13172708Swollman	tmp->TM_GMTOFF = offset;
13182708Swollman#endif /* defined TM_GMTOFF */
13192708Swollman}
13202708Swollman
13212708Swollmanchar *
13222708Swollmanctime(timep)
13232708Swollmanconst time_t * const	timep;
13242708Swollman{
13259936Swollman/*
13269936Swollman** Section 4.12.3.2 of X3.159-1989 requires that
13279936Swollman**	The ctime funciton converts the calendar time pointed to by timer
13289936Swollman**	to local time in the form of a string.  It is equivalent to
13299936Swollman**		asctime(localtime(timer))
13309936Swollman*/
13312708Swollman	return asctime(localtime(timep));
13322708Swollman}
13332708Swollman
13342708Swollman/*
13352708Swollman** Adapted from code provided by Robert Elz, who writes:
13362708Swollman**	The "best" way to do mktime I think is based on an idea of Bob
13372708Swollman**	Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
13382708Swollman**	It does a binary search of the time_t space.  Since time_t's are
13392708Swollman**	just 32 bits, its a max of 32 iterations (even at 64 bits it
13402708Swollman**	would still be very reasonable).
13412708Swollman*/
13422708Swollman
13432708Swollman#ifndef WRONG
13442708Swollman#define WRONG	(-1)
13452708Swollman#endif /* !defined WRONG */
13462708Swollman
13472708Swollman/*
13482708Swollman** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
13492708Swollman*/
13502708Swollman
13512708Swollmanstatic int
13522708Swollmanincrement_overflow(number, delta)
13532708Swollmanint *	number;
13542708Swollmanint	delta;
13552708Swollman{
13569936Swollman	int	number0;
13578870Srgrimes
13582708Swollman	number0 = *number;
13592708Swollman	*number += delta;
13602708Swollman	return (*number < number0) != (delta < 0);
13612708Swollman}
13622708Swollman
13632708Swollmanstatic int
13642708Swollmannormalize_overflow(tensptr, unitsptr, base)
13652708Swollmanint * const	tensptr;
13662708Swollmanint * const	unitsptr;
13672708Swollmanconst int	base;
13682708Swollman{
13692708Swollman	register int	tensdelta;
13702708Swollman
13712708Swollman	tensdelta = (*unitsptr >= 0) ?
13722708Swollman		(*unitsptr / base) :
13732708Swollman		(-1 - (-1 - *unitsptr) / base);
13742708Swollman	*unitsptr -= tensdelta * base;
13752708Swollman	return increment_overflow(tensptr, tensdelta);
13762708Swollman}
13772708Swollman
13782708Swollmanstatic int
13792708Swollmantmcomp(atmp, btmp)
13802708Swollmanregister const struct tm * const atmp;
13812708Swollmanregister const struct tm * const btmp;
13822708Swollman{
13832708Swollman	register int	result;
13842708Swollman
13852708Swollman	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
13862708Swollman		(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
13872708Swollman		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
13882708Swollman		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
13892708Swollman		(result = (atmp->tm_min - btmp->tm_min)) == 0)
13902708Swollman			result = atmp->tm_sec - btmp->tm_sec;
13912708Swollman	return result;
13922708Swollman}
13932708Swollman
13942708Swollmanstatic time_t
13952708Swollmantime2(tmp, funcp, offset, okayp)
13962708Swollmanstruct tm * const	tmp;
13979936Swollmanvoid (* const		funcp) P((const time_t*, long, struct tm*));
13982708Swollmanconst long		offset;
13992708Swollmanint * const		okayp;
14002708Swollman{
14012708Swollman	register const struct state *	sp;
14022708Swollman	register int			dir;
14032708Swollman	register int			bits;
14042708Swollman	register int			i, j ;
14052708Swollman	register int			saved_seconds;
14062708Swollman	time_t				newt;
14072708Swollman	time_t				t;
14082708Swollman	struct tm			yourtm, mytm;
14092708Swollman
14102708Swollman	*okayp = FALSE;
14112708Swollman	yourtm = *tmp;
14122708Swollman	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
14132708Swollman		return WRONG;
14142708Swollman	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
14152708Swollman		return WRONG;
14162708Swollman	if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
14172708Swollman		return WRONG;
14182708Swollman	/*
14192708Swollman	** Turn yourtm.tm_year into an actual year number for now.
14202708Swollman	** It is converted back to an offset from TM_YEAR_BASE later.
14212708Swollman	*/
14222708Swollman	if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
14232708Swollman		return WRONG;
14242708Swollman	while (yourtm.tm_mday <= 0) {
14252708Swollman		if (increment_overflow(&yourtm.tm_year, -1))
14262708Swollman			return WRONG;
14272708Swollman		yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)];
14282708Swollman	}
14292708Swollman	while (yourtm.tm_mday > DAYSPERLYEAR) {
14302708Swollman		yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)];
14312708Swollman		if (increment_overflow(&yourtm.tm_year, 1))
14322708Swollman			return WRONG;
14332708Swollman	}
14342708Swollman	for ( ; ; ) {
14352708Swollman		i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
14362708Swollman		if (yourtm.tm_mday <= i)
14372708Swollman			break;
14382708Swollman		yourtm.tm_mday -= i;
14392708Swollman		if (++yourtm.tm_mon >= MONSPERYEAR) {
14402708Swollman			yourtm.tm_mon = 0;
14412708Swollman			if (increment_overflow(&yourtm.tm_year, 1))
14422708Swollman				return WRONG;
14432708Swollman		}
14442708Swollman	}
14452708Swollman	if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
14462708Swollman		return WRONG;
14472708Swollman	if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
14482708Swollman		/*
14492708Swollman		** We can't set tm_sec to 0, because that might push the
14502708Swollman		** time below the minimum representable time.
14512708Swollman		** Set tm_sec to 59 instead.
14522708Swollman		** This assumes that the minimum representable time is
14532708Swollman		** not in the same minute that a leap second was deleted from,
14542708Swollman		** which is a safer assumption than using 58 would be.
14552708Swollman		*/
14562708Swollman		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
14572708Swollman			return WRONG;
14582708Swollman		saved_seconds = yourtm.tm_sec;
14592708Swollman		yourtm.tm_sec = SECSPERMIN - 1;
14602708Swollman	} else {
14612708Swollman		saved_seconds = yourtm.tm_sec;
14622708Swollman		yourtm.tm_sec = 0;
14632708Swollman	}
14642708Swollman	/*
14652708Swollman	** Calculate the number of magnitude bits in a time_t
14662708Swollman	** (this works regardless of whether time_t is
14672708Swollman	** signed or unsigned, though lint complains if unsigned).
14682708Swollman	*/
14692708Swollman	for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
14702708Swollman		continue;
14712708Swollman	/*
14722708Swollman	** If time_t is signed, then 0 is the median value,
14732708Swollman	** if time_t is unsigned, then 1 << bits is median.
14742708Swollman	*/
14752708Swollman	t = (t < 0) ? 0 : ((time_t) 1 << bits);
14762708Swollman	for ( ; ; ) {
14772708Swollman		(*funcp)(&t, offset, &mytm);
14782708Swollman		dir = tmcomp(&mytm, &yourtm);
14792708Swollman		if (dir != 0) {
14802708Swollman			if (bits-- < 0)
14812708Swollman				return WRONG;
14822708Swollman			if (bits < 0)
14832708Swollman				--t;
14842708Swollman			else if (dir > 0)
14852708Swollman				t -= (time_t) 1 << bits;
14862708Swollman			else	t += (time_t) 1 << bits;
14872708Swollman			continue;
14882708Swollman		}
14892708Swollman		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
14902708Swollman			break;
14912708Swollman		/*
14922708Swollman		** Right time, wrong type.
14932708Swollman		** Hunt for right time, right type.
14942708Swollman		** It's okay to guess wrong since the guess
14952708Swollman		** gets checked.
14962708Swollman		*/
14972708Swollman		/*
14982708Swollman		** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
14992708Swollman		*/
15002708Swollman		sp = (const struct state *)
15012708Swollman			(((void *) funcp == (void *) localsub) ?
15022708Swollman			lclptr : gmtptr);
15032708Swollman#ifdef ALL_STATE
15042708Swollman		if (sp == NULL)
15052708Swollman			return WRONG;
15062708Swollman#endif /* defined ALL_STATE */
15072708Swollman		for (i = 0; i < sp->typecnt; ++i) {
15082708Swollman			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
15092708Swollman				continue;
15102708Swollman			for (j = 0; j < sp->typecnt; ++j) {
15112708Swollman				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
15122708Swollman					continue;
15132708Swollman				newt = t + sp->ttis[j].tt_gmtoff -
15142708Swollman					sp->ttis[i].tt_gmtoff;
15152708Swollman				(*funcp)(&newt, offset, &mytm);
15162708Swollman				if (tmcomp(&mytm, &yourtm) != 0)
15172708Swollman					continue;
15182708Swollman				if (mytm.tm_isdst != yourtm.tm_isdst)
15192708Swollman					continue;
15202708Swollman				/*
15212708Swollman				** We have a match.
15222708Swollman				*/
15232708Swollman				t = newt;
15242708Swollman				goto label;
15252708Swollman			}
15262708Swollman		}
15272708Swollman		return WRONG;
15282708Swollman	}
15292708Swollmanlabel:
15302708Swollman	newt = t + saved_seconds;
15312708Swollman	if ((newt < t) != (saved_seconds < 0))
15322708Swollman		return WRONG;
15332708Swollman	t = newt;
15342708Swollman	(*funcp)(&t, offset, tmp);
15352708Swollman	*okayp = TRUE;
15362708Swollman	return t;
15372708Swollman}
15382708Swollman
15392708Swollmanstatic time_t
15402708Swollmantime1(tmp, funcp, offset)
15412708Swollmanstruct tm * const	tmp;
15429936Swollmanvoid (* const		funcp) P((const time_t*, long, struct tm*));
15432708Swollmanconst long		offset;
15442708Swollman{
15452708Swollman	register time_t			t;
15462708Swollman	register const struct state *	sp;
15472708Swollman	register int			samei, otheri;
15482708Swollman	int				okay;
15492708Swollman
15502708Swollman	if (tmp->tm_isdst > 1)
15512708Swollman		tmp->tm_isdst = 1;
15522708Swollman	t = time2(tmp, funcp, offset, &okay);
15532708Swollman#ifdef PCTS
15542708Swollman	/*
15552708Swollman	** PCTS code courtesy Grant Sullivan (grant@osf.org).
15562708Swollman	*/
15572708Swollman	if (okay)
15582708Swollman		return t;
15592708Swollman	if (tmp->tm_isdst < 0)
15602708Swollman		tmp->tm_isdst = 0;	/* reset to std and try again */
15612708Swollman#endif /* defined PCTS */
15622708Swollman#ifndef PCTS
15632708Swollman	if (okay || tmp->tm_isdst < 0)
15642708Swollman		return t;
15652708Swollman#endif /* !defined PCTS */
15662708Swollman	/*
15672708Swollman	** We're supposed to assume that somebody took a time of one type
15682708Swollman	** and did some math on it that yielded a "struct tm" that's bad.
15692708Swollman	** We try to divine the type they started from and adjust to the
15702708Swollman	** type they need.
15712708Swollman	*/
15722708Swollman	/*
15732708Swollman	** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
15742708Swollman	*/
15752708Swollman	sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
15762708Swollman		lclptr : gmtptr);
15772708Swollman#ifdef ALL_STATE
15782708Swollman	if (sp == NULL)
15792708Swollman		return WRONG;
15802708Swollman#endif /* defined ALL_STATE */
15812708Swollman	for (samei = 0; samei < sp->typecnt; ++samei) {
15822708Swollman		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
15832708Swollman			continue;
15842708Swollman		for (otheri = 0; otheri < sp->typecnt; ++otheri) {
15852708Swollman			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
15862708Swollman				continue;
15872708Swollman			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
15882708Swollman					sp->ttis[samei].tt_gmtoff;
15892708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
15902708Swollman			t = time2(tmp, funcp, offset, &okay);
15912708Swollman			if (okay)
15922708Swollman				return t;
15932708Swollman			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
15942708Swollman					sp->ttis[samei].tt_gmtoff;
15952708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
15962708Swollman		}
15972708Swollman	}
15982708Swollman	return WRONG;
15992708Swollman}
16002708Swollman
16012708Swollmantime_t
16022708Swollmanmktime(tmp)
16032708Swollmanstruct tm * const	tmp;
16042708Swollman{
160513545Sjulian	time_t mktime_return_value;
160613545Sjulian#ifdef	_THREAD_SAFE
160713545Sjulian	pthread_mutex_lock(&lcl_mutex);
160813545Sjulian#endif
16099936Swollman	tzset();
161013545Sjulian	mktime_return_value = time1(tmp, localsub, 0L);
161113545Sjulian#ifdef	_THREAD_SAFE
161213545Sjulian	pthread_mutex_unlock(&lcl_mutex);
161313545Sjulian#endif
161413545Sjulian	return(mktime_return_value);
16152708Swollman}
16162708Swollman
16172708Swollman#ifdef STD_INSPIRED
16182708Swollman
16192708Swollmantime_t
16202708Swollmantimelocal(tmp)
16212708Swollmanstruct tm * const	tmp;
16222708Swollman{
16232708Swollman	tmp->tm_isdst = -1;	/* in case it wasn't initialized */
16242708Swollman	return mktime(tmp);
16252708Swollman}
16262708Swollman
16272708Swollmantime_t
16282708Swollmantimegm(tmp)
16292708Swollmanstruct tm * const	tmp;
16302708Swollman{
16312708Swollman	tmp->tm_isdst = 0;
16322708Swollman	return time1(tmp, gmtsub, 0L);
16332708Swollman}
16342708Swollman
16352708Swollmantime_t
16362708Swollmantimeoff(tmp, offset)
16372708Swollmanstruct tm * const	tmp;
16382708Swollmanconst long		offset;
16392708Swollman{
16402708Swollman	tmp->tm_isdst = 0;
16412708Swollman	return time1(tmp, gmtsub, offset);
16422708Swollman}
16432708Swollman
16442708Swollman#endif /* defined STD_INSPIRED */
16452708Swollman
16462708Swollman#ifdef CMUCS
16472708Swollman
16482708Swollman/*
16492708Swollman** The following is supplied for compatibility with
16502708Swollman** previous versions of the CMUCS runtime library.
16512708Swollman*/
16522708Swollman
16532708Swollmanlong
16542708Swollmangtime(tmp)
16552708Swollmanstruct tm * const	tmp;
16562708Swollman{
16572708Swollman	const time_t	t = mktime(tmp);
16582708Swollman
16592708Swollman	if (t == WRONG)
16602708Swollman		return -1;
16612708Swollman	return t;
16622708Swollman}
16632708Swollman
16642708Swollman#endif /* defined CMUCS */
16652708Swollman
16662708Swollman/*
16672708Swollman** XXX--is the below the right way to conditionalize??
16682708Swollman*/
16692708Swollman
16702708Swollman#ifdef STD_INSPIRED
16712708Swollman
16722708Swollman/*
16732708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
16742708Swollman** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
16752708Swollman** is not the case if we are accounting for leap seconds.
16762708Swollman** So, we provide the following conversion routines for use
16772708Swollman** when exchanging timestamps with POSIX conforming systems.
16782708Swollman*/
16792708Swollman
16802708Swollmanstatic long
16812708Swollmanleapcorr(timep)
16822708Swollmantime_t *	timep;
16832708Swollman{
16842708Swollman	register struct state *		sp;
16852708Swollman	register struct lsinfo *	lp;
16862708Swollman	register int			i;
16872708Swollman
16882708Swollman	sp = lclptr;
16892708Swollman	i = sp->leapcnt;
16902708Swollman	while (--i >= 0) {
16912708Swollman		lp = &sp->lsis[i];
16922708Swollman		if (*timep >= lp->ls_trans)
16932708Swollman			return lp->ls_corr;
16942708Swollman	}
16952708Swollman	return 0;
16962708Swollman}
16972708Swollman
16982708Swollmantime_t
16992708Swollmantime2posix(t)
17002708Swollmantime_t	t;
17012708Swollman{
17029936Swollman	tzset();
17032708Swollman	return t - leapcorr(&t);
17042708Swollman}
17052708Swollman
17062708Swollmantime_t
17072708Swollmanposix2time(t)
17082708Swollmantime_t	t;
17092708Swollman{
17102708Swollman	time_t	x;
17112708Swollman	time_t	y;
17122708Swollman
17139936Swollman	tzset();
17142708Swollman	/*
17152708Swollman	** For a positive leap second hit, the result
17162708Swollman	** is not unique.  For a negative leap second
17172708Swollman	** hit, the corresponding time doesn't exist,
17182708Swollman	** so we return an adjacent second.
17192708Swollman	*/
17202708Swollman	x = t + leapcorr(&t);
17212708Swollman	y = x - leapcorr(&x);
17222708Swollman	if (y < t) {
17232708Swollman		do {
17242708Swollman			x++;
17252708Swollman			y = x - leapcorr(&x);
17262708Swollman		} while (y < t);
17272708Swollman		if (t != y)
17282708Swollman			return x - 1;
17292708Swollman	} else if (y > t) {
17302708Swollman		do {
17312708Swollman			--x;
17322708Swollman			y = x - leapcorr(&x);
17332708Swollman		} while (y > t);
17342708Swollman		if (t != y)
17352708Swollman			return x + 1;
17362708Swollman	}
17372708Swollman	return x;
17382708Swollman}
17392708Swollman
17402708Swollman#endif /* defined STD_INSPIRED */
1741