localtime.c revision 9936
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"
182708Swollman
199936Swollman/*
209936Swollman** SunOS 4.1.1 headers lack O_BINARY.
219936Swollman*/
222708Swollman
232708Swollman#ifdef O_BINARY
242708Swollman#define OPEN_MODE	(O_RDONLY | O_BINARY)
252708Swollman#endif /* defined O_BINARY */
262708Swollman#ifndef O_BINARY
272708Swollman#define OPEN_MODE	O_RDONLY
282708Swollman#endif /* !defined O_BINARY */
292708Swollman
302708Swollman#ifndef WILDABBR
312708Swollman/*
322708Swollman** Someone might make incorrect use of a time zone abbreviation:
332708Swollman**	1.	They might reference tzname[0] before calling tzset (explicitly
349936Swollman**		or implicitly).
352708Swollman**	2.	They might reference tzname[1] before calling tzset (explicitly
369936Swollman**		or implicitly).
372708Swollman**	3.	They might reference tzname[1] after setting to a time zone
382708Swollman**		in which Daylight Saving Time is never observed.
392708Swollman**	4.	They might reference tzname[0] after setting to a time zone
402708Swollman**		in which Standard Time is never observed.
412708Swollman**	5.	They might reference tm.TM_ZONE after calling offtime.
422708Swollman** What's best to do in the above cases is open to debate;
432708Swollman** for now, we just set things up so that in any of the five cases
442708Swollman** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
452708Swollman** string "tzname[0] used before set", and similarly for the other cases.
462708Swollman** And another:  initialize tzname[0] to "ERA", with an explanation in the
472708Swollman** manual page of what this "time zone abbreviation" means (doing this so
482708Swollman** that tzname[0] has the "normal" length of three characters).
492708Swollman*/
502708Swollman#define WILDABBR	"   "
512708Swollman#endif /* !defined WILDABBR */
522708Swollman
539936Swollmanstatic char		wildabbr[] = "WILDABBR";
542708Swollman
559936Swollmanstatic const char	gmt[] = "GMT";
569936Swollman
572708Swollmanstruct ttinfo {				/* time type information */
582708Swollman	long		tt_gmtoff;	/* GMT offset in seconds */
592708Swollman	int		tt_isdst;	/* used to set tm_isdst */
602708Swollman	int		tt_abbrind;	/* abbreviation list index */
612708Swollman	int		tt_ttisstd;	/* TRUE if transition is std time */
629936Swollman	int		tt_ttisgmt;	/* TRUE if transition is GMT */
632708Swollman};
642708Swollman
652708Swollmanstruct lsinfo {				/* leap second information */
662708Swollman	time_t		ls_trans;	/* transition time */
672708Swollman	long		ls_corr;	/* correction to apply */
682708Swollman};
692708Swollman
702708Swollman#define BIGGEST(a, b)	(((a) > (b)) ? (a) : (b))
712708Swollman
722708Swollman#ifdef TZNAME_MAX
732708Swollman#define MY_TZNAME_MAX	TZNAME_MAX
742708Swollman#endif /* defined TZNAME_MAX */
752708Swollman#ifndef TZNAME_MAX
762708Swollman#define MY_TZNAME_MAX	255
772708Swollman#endif /* !defined TZNAME_MAX */
782708Swollman
792708Swollmanstruct state {
802708Swollman	int		leapcnt;
812708Swollman	int		timecnt;
822708Swollman	int		typecnt;
832708Swollman	int		charcnt;
842708Swollman	time_t		ats[TZ_MAX_TIMES];
852708Swollman	unsigned char	types[TZ_MAX_TIMES];
862708Swollman	struct ttinfo	ttis[TZ_MAX_TYPES];
879936Swollman	char		chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
882708Swollman				(2 * (MY_TZNAME_MAX + 1)))];
892708Swollman	struct lsinfo	lsis[TZ_MAX_LEAPS];
902708Swollman};
912708Swollman
922708Swollmanstruct rule {
932708Swollman	int		r_type;		/* type of rule--see below */
942708Swollman	int		r_day;		/* day number of rule */
952708Swollman	int		r_week;		/* week number of rule */
962708Swollman	int		r_mon;		/* month number of rule */
972708Swollman	long		r_time;		/* transition time of rule */
982708Swollman};
992708Swollman
1002708Swollman#define JULIAN_DAY		0	/* Jn - Julian day */
1012708Swollman#define DAY_OF_YEAR		1	/* n - day of year */
1022708Swollman#define MONTH_NTH_DAY_OF_WEEK	2	/* Mm.n.d - month, week, day of week */
1032708Swollman
1042708Swollman/*
1052708Swollman** Prototypes for static functions.
1062708Swollman*/
1072708Swollman
1082708Swollmanstatic long		detzcode P((const char * codep));
1092708Swollmanstatic const char *	getzname P((const char * strp));
1102708Swollmanstatic const char *	getnum P((const char * strp, int * nump, int min,
1112708Swollman				int max));
1122708Swollmanstatic const char *	getsecs P((const char * strp, long * secsp));
1132708Swollmanstatic const char *	getoffset P((const char * strp, long * offsetp));
1142708Swollmanstatic const char *	getrule P((const char * strp, struct rule * rulep));
1152708Swollmanstatic void		gmtload P((struct state * sp));
1162708Swollmanstatic void		gmtsub P((const time_t * timep, long offset,
1172708Swollman				struct tm * tmp));
1182708Swollmanstatic void		localsub P((const time_t * timep, long offset,
1192708Swollman				struct tm * tmp));
1202708Swollmanstatic int		increment_overflow P((int * number, int delta));
1212708Swollmanstatic int		normalize_overflow P((int * tensptr, int * unitsptr,
1222708Swollman				int base));
1232708Swollmanstatic void		settzname P((void));
1249936Swollmanstatic time_t		time1 P((struct tm * tmp,
1259936Swollman				void(*funcp) P((const time_t *,
1269936Swollman				long, struct tm *)),
1272708Swollman				long offset));
1289936Swollmanstatic time_t		time2 P((struct tm *tmp,
1299936Swollman				void(*funcp) P((const time_t *,
1309936Swollman				long, struct tm*)),
1312708Swollman				long offset, int * okayp));
1322708Swollmanstatic void		timesub P((const time_t * timep, long offset,
1332708Swollman				const struct state * sp, struct tm * tmp));
1342708Swollmanstatic int		tmcomp P((const struct tm * atmp,
1352708Swollman				const struct tm * btmp));
1362708Swollmanstatic time_t		transtime P((time_t janfirst, int year,
1372708Swollman				const struct rule * rulep, long offset));
1382708Swollmanstatic int		tzload P((const char * name, struct state * sp));
1392708Swollmanstatic int		tzparse P((const char * name, struct state * sp,
1402708Swollman				int lastditch));
1412708Swollman
1422708Swollman#ifdef ALL_STATE
1432708Swollmanstatic struct state *	lclptr;
1442708Swollmanstatic struct state *	gmtptr;
1452708Swollman#endif /* defined ALL_STATE */
1462708Swollman
1472708Swollman#ifndef ALL_STATE
1482708Swollmanstatic struct state	lclmem;
1492708Swollmanstatic struct state	gmtmem;
1502708Swollman#define lclptr		(&lclmem)
1512708Swollman#define gmtptr		(&gmtmem)
1522708Swollman#endif /* State Farm */
1532708Swollman
1549936Swollman#ifndef TZ_STRLEN_MAX
1559936Swollman#define TZ_STRLEN_MAX 255
1569936Swollman#endif /* !defined TZ_STRLEN_MAX */
1579936Swollman
1589936Swollmanstatic char		lcl_TZname[TZ_STRLEN_MAX + 1];
1592708Swollmanstatic int		lcl_is_set;
1602708Swollmanstatic int		gmt_is_set;
1612708Swollman
1622708Swollmanchar *			tzname[2] = {
1639936Swollman	wildabbr,
1649936Swollman	wildabbr
1652708Swollman};
1662708Swollman
1679936Swollman/*
1689936Swollman** Section 4.12.3 of X3.159-1989 requires that
1699936Swollman**	Except for the strftime function, these functions [asctime,
1709936Swollman**	ctime, gmtime, localtime] return values in one of two static
1719936Swollman**	objects: a broken-down time structure and an array of char.
1729936Swollman** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
1739936Swollman*/
1749936Swollman
1759936Swollmanstatic struct tm	tm;
1769936Swollman
1772708Swollman#ifdef USG_COMPAT
1782708Swollmantime_t			timezone = 0;
1792708Swollmanint			daylight = 0;
1802708Swollman#endif /* defined USG_COMPAT */
1812708Swollman
1822708Swollman#ifdef ALTZONE
1832708Swollmantime_t			altzone = 0;
1842708Swollman#endif /* defined ALTZONE */
1852708Swollman
1862708Swollmanstatic long
1872708Swollmandetzcode(codep)
1882708Swollmanconst char * const	codep;
1892708Swollman{
1902708Swollman	register long	result;
1912708Swollman	register int	i;
1922708Swollman
1939936Swollman 	result = (codep[0] & 0x80) ? ~0L : 0L;
1942708Swollman	for (i = 0; i < 4; ++i)
1952708Swollman		result = (result << 8) | (codep[i] & 0xff);
1962708Swollman	return result;
1972708Swollman}
1982708Swollman
1992708Swollmanstatic void
2009936Swollmansettzname P((void))
2012708Swollman{
2029936Swollman	register struct state * const		sp = lclptr;
2032708Swollman	register int				i;
2042708Swollman
2059936Swollman	tzname[0] = wildabbr;
2069936Swollman	tzname[1] = wildabbr;
2072708Swollman#ifdef USG_COMPAT
2082708Swollman	daylight = 0;
2092708Swollman	timezone = 0;
2102708Swollman#endif /* defined USG_COMPAT */
2112708Swollman#ifdef ALTZONE
2122708Swollman	altzone = 0;
2132708Swollman#endif /* defined ALTZONE */
2142708Swollman#ifdef ALL_STATE
2152708Swollman	if (sp == NULL) {
2169936Swollman		tzname[0] = tzname[1] = gmt;
2172708Swollman		return;
2182708Swollman	}
2192708Swollman#endif /* defined ALL_STATE */
2202708Swollman	for (i = 0; i < sp->typecnt; ++i) {
2212708Swollman		register const struct ttinfo * const	ttisp = &sp->ttis[i];
2222708Swollman
2232708Swollman		tzname[ttisp->tt_isdst] =
2249936Swollman			&sp->chars[ttisp->tt_abbrind];
2252708Swollman#ifdef USG_COMPAT
2262708Swollman		if (ttisp->tt_isdst)
2272708Swollman			daylight = 1;
2282708Swollman		if (i == 0 || !ttisp->tt_isdst)
2292708Swollman			timezone = -(ttisp->tt_gmtoff);
2302708Swollman#endif /* defined USG_COMPAT */
2312708Swollman#ifdef ALTZONE
2322708Swollman		if (i == 0 || ttisp->tt_isdst)
2332708Swollman			altzone = -(ttisp->tt_gmtoff);
2342708Swollman#endif /* defined ALTZONE */
2352708Swollman	}
2362708Swollman	/*
2372708Swollman	** And to get the latest zone names into tzname. . .
2382708Swollman	*/
2392708Swollman	for (i = 0; i < sp->timecnt; ++i) {
2402708Swollman		register const struct ttinfo * const	ttisp =
2412708Swollman							&sp->ttis[
2422708Swollman								sp->types[i]];
2432708Swollman
2442708Swollman		tzname[ttisp->tt_isdst] =
2459936Swollman			&sp->chars[ttisp->tt_abbrind];
2462708Swollman	}
2472708Swollman}
2482708Swollman
2492708Swollmanstatic int
2502708Swollmantzload(name, sp)
2512708Swollmanregister const char *		name;
2522708Swollmanregister struct state * const	sp;
2532708Swollman{
2542708Swollman	register const char *	p;
2552708Swollman	register int		i;
2562708Swollman	register int		fid;
2572708Swollman
2582708Swollman	if (name == NULL && (name = TZDEFAULT) == NULL)
2592708Swollman		return -1;
2602708Swollman	{
2619936Swollman		register int	doaccess;
2629936Swollman		/*
2639936Swollman		** Section 4.9.1 of the C standard says that
2649936Swollman		** "FILENAME_MAX expands to an integral constant expression
2659936Swollman		** that is the sie needed for an array of char large enough
2669936Swollman		** to hold the longest file name string that the implementation
2679936Swollman		** guarantees can be opened."
2689936Swollman		*/
2692708Swollman		char		fullname[FILENAME_MAX + 1];
2702708Swollman
2712708Swollman		if (name[0] == ':')
2722708Swollman			++name;
2732708Swollman		doaccess = name[0] == '/';
2742708Swollman		if (!doaccess) {
2752708Swollman			if ((p = TZDIR) == NULL)
2762708Swollman				return -1;
2772708Swollman			if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
2782708Swollman				return -1;
2792708Swollman			(void) strcpy(fullname, p);
2802708Swollman			(void) strcat(fullname, "/");
2812708Swollman			(void) strcat(fullname, name);
2822708Swollman			/*
2832708Swollman			** Set doaccess if '.' (as in "../") shows up in name.
2842708Swollman			*/
2852708Swollman			if (strchr(name, '.') != NULL)
2862708Swollman				doaccess = TRUE;
2872708Swollman			name = fullname;
2882708Swollman		}
2899936Swollman		if (doaccess && access(name, R_OK) != 0)
2902708Swollman			return -1;
2912708Swollman		if ((fid = open(name, OPEN_MODE)) == -1)
2922708Swollman			return -1;
2932708Swollman	}
2942708Swollman	{
2959936Swollman		struct tzhead *	tzhp;
2969936Swollman		char		buf[sizeof *sp + sizeof *tzhp];
2979936Swollman		int		ttisstdcnt;
2989936Swollman		int		ttisgmtcnt;
2992708Swollman
3002708Swollman		i = read(fid, buf, sizeof buf);
3019936Swollman		if (close(fid) != 0)
3022708Swollman			return -1;
3039936Swollman		p = buf;
3049936Swollman		p += sizeof tzhp->tzh_reserved;
3059936Swollman		ttisstdcnt = (int) detzcode(p);
3069936Swollman		p += 4;
3079936Swollman		ttisgmtcnt = (int) detzcode(p);
3089936Swollman		p += 4;
3099936Swollman		sp->leapcnt = (int) detzcode(p);
3109936Swollman		p += 4;
3119936Swollman		sp->timecnt = (int) detzcode(p);
3129936Swollman		p += 4;
3139936Swollman		sp->typecnt = (int) detzcode(p);
3149936Swollman		p += 4;
3159936Swollman		sp->charcnt = (int) detzcode(p);
3169936Swollman		p += 4;
3172708Swollman		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
3182708Swollman			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
3192708Swollman			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
3202708Swollman			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
3219936Swollman			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
3229936Swollman			(ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
3232708Swollman				return -1;
3249936Swollman		if (i - (p - buf) < sp->timecnt * 4 +	/* ats */
3259936Swollman			sp->timecnt +			/* types */
3269936Swollman			sp->typecnt * (4 + 2) +		/* ttinfos */
3279936Swollman			sp->charcnt +			/* chars */
3289936Swollman			sp->leapcnt * (4 + 4) +		/* lsinfos */
3299936Swollman			ttisstdcnt +			/* ttisstds */
3309936Swollman			ttisgmtcnt)			/* ttisgmts */
3312708Swollman				return -1;
3322708Swollman		for (i = 0; i < sp->timecnt; ++i) {
3332708Swollman			sp->ats[i] = detzcode(p);
3342708Swollman			p += 4;
3352708Swollman		}
3362708Swollman		for (i = 0; i < sp->timecnt; ++i) {
3372708Swollman			sp->types[i] = (unsigned char) *p++;
3382708Swollman			if (sp->types[i] >= sp->typecnt)
3392708Swollman				return -1;
3402708Swollman		}
3412708Swollman		for (i = 0; i < sp->typecnt; ++i) {
3422708Swollman			register struct ttinfo *	ttisp;
3432708Swollman
3442708Swollman			ttisp = &sp->ttis[i];
3452708Swollman			ttisp->tt_gmtoff = detzcode(p);
3462708Swollman			p += 4;
3472708Swollman			ttisp->tt_isdst = (unsigned char) *p++;
3482708Swollman			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
3492708Swollman				return -1;
3502708Swollman			ttisp->tt_abbrind = (unsigned char) *p++;
3512708Swollman			if (ttisp->tt_abbrind < 0 ||
3522708Swollman				ttisp->tt_abbrind > sp->charcnt)
3532708Swollman					return -1;
3542708Swollman		}
3552708Swollman		for (i = 0; i < sp->charcnt; ++i)
3562708Swollman			sp->chars[i] = *p++;
3572708Swollman		sp->chars[i] = '\0';	/* ensure '\0' at end */
3582708Swollman		for (i = 0; i < sp->leapcnt; ++i) {
3592708Swollman			register struct lsinfo *	lsisp;
3602708Swollman
3612708Swollman			lsisp = &sp->lsis[i];
3622708Swollman			lsisp->ls_trans = detzcode(p);
3632708Swollman			p += 4;
3642708Swollman			lsisp->ls_corr = detzcode(p);
3652708Swollman			p += 4;
3662708Swollman		}
3672708Swollman		for (i = 0; i < sp->typecnt; ++i) {
3682708Swollman			register struct ttinfo *	ttisp;
3692708Swollman
3702708Swollman			ttisp = &sp->ttis[i];
3712708Swollman			if (ttisstdcnt == 0)
3722708Swollman				ttisp->tt_ttisstd = FALSE;
3732708Swollman			else {
3742708Swollman				ttisp->tt_ttisstd = *p++;
3752708Swollman				if (ttisp->tt_ttisstd != TRUE &&
3762708Swollman					ttisp->tt_ttisstd != FALSE)
3772708Swollman						return -1;
3782708Swollman			}
3792708Swollman		}
3809936Swollman		for (i = 0; i < sp->typecnt; ++i) {
3819936Swollman			register struct ttinfo *	ttisp;
3829936Swollman
3839936Swollman			ttisp = &sp->ttis[i];
3849936Swollman			if (ttisgmtcnt == 0)
3859936Swollman				ttisp->tt_ttisgmt = FALSE;
3869936Swollman			else {
3879936Swollman				ttisp->tt_ttisgmt = *p++;
3889936Swollman				if (ttisp->tt_ttisgmt != TRUE &&
3899936Swollman					ttisp->tt_ttisgmt != FALSE)
3909936Swollman						return -1;
3919936Swollman			}
3929936Swollman		}
3932708Swollman	}
3942708Swollman	return 0;
3952708Swollman}
3962708Swollman
3972708Swollmanstatic const int	mon_lengths[2][MONSPERYEAR] = {
3982708Swollman	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3992708Swollman	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
4002708Swollman};
4012708Swollman
4022708Swollmanstatic const int	year_lengths[2] = {
4032708Swollman	DAYSPERNYEAR, DAYSPERLYEAR
4042708Swollman};
4052708Swollman
4062708Swollman/*
4072708Swollman** Given a pointer into a time zone string, scan until a character that is not
4082708Swollman** a valid character in a zone name is found.  Return a pointer to that
4092708Swollman** character.
4102708Swollman*/
4112708Swollman
4122708Swollmanstatic const char *
4132708Swollmangetzname(strp)
4142708Swollmanregister const char *	strp;
4152708Swollman{
4162708Swollman	register char	c;
4172708Swollman
4182708Swollman	while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
4192708Swollman		c != '+')
4202708Swollman			++strp;
4212708Swollman	return strp;
4222708Swollman}
4232708Swollman
4242708Swollman/*
4252708Swollman** Given a pointer into a time zone string, extract a number from that string.
4262708Swollman** Check that the number is within a specified range; if it is not, return
4272708Swollman** NULL.
4282708Swollman** Otherwise, return a pointer to the first character not part of the number.
4292708Swollman*/
4302708Swollman
4312708Swollmanstatic const char *
4322708Swollmangetnum(strp, nump, min, max)
4332708Swollmanregister const char *	strp;
4342708Swollmanint * const		nump;
4352708Swollmanconst int		min;
4362708Swollmanconst int		max;
4372708Swollman{
4382708Swollman	register char	c;
4392708Swollman	register int	num;
4402708Swollman
4412708Swollman	if (strp == NULL || !isdigit(*strp))
4422708Swollman		return NULL;
4432708Swollman	num = 0;
4442708Swollman	while ((c = *strp) != '\0' && isdigit(c)) {
4452708Swollman		num = num * 10 + (c - '0');
4462708Swollman		if (num > max)
4472708Swollman			return NULL;	/* illegal value */
4482708Swollman		++strp;
4492708Swollman	}
4502708Swollman	if (num < min)
4512708Swollman		return NULL;		/* illegal value */
4522708Swollman	*nump = num;
4532708Swollman	return strp;
4542708Swollman}
4552708Swollman
4562708Swollman/*
4572708Swollman** Given a pointer into a time zone string, extract a number of seconds,
4582708Swollman** in hh[:mm[:ss]] form, from the string.
4592708Swollman** If any error occurs, return NULL.
4602708Swollman** Otherwise, return a pointer to the first character not part of the number
4612708Swollman** of seconds.
4622708Swollman*/
4632708Swollman
4642708Swollmanstatic const char *
4652708Swollmangetsecs(strp, secsp)
4662708Swollmanregister const char *	strp;
4672708Swollmanlong * const		secsp;
4682708Swollman{
4692708Swollman	int	num;
4702708Swollman
4719936Swollman	/*
4729936Swollman	** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
4739936Swollman	** "M10.4.6/26", which does not conform to Posix,
4749936Swollman	** but which specifies the equivalent of
4759936Swollman	** ``02:00 on the first Sunday on or after 23 Oct''.
4769936Swollman	*/
4779936Swollman	strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
4782708Swollman	if (strp == NULL)
4792708Swollman		return NULL;
4809936Swollman	*secsp = num * (long) SECSPERHOUR;
4812708Swollman	if (*strp == ':') {
4822708Swollman		++strp;
4832708Swollman		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
4842708Swollman		if (strp == NULL)
4852708Swollman			return NULL;
4862708Swollman		*secsp += num * SECSPERMIN;
4872708Swollman		if (*strp == ':') {
4882708Swollman			++strp;
4899936Swollman			/* `SECSPERMIN' allows for leap seconds.  */
4909936Swollman			strp = getnum(strp, &num, 0, SECSPERMIN);
4912708Swollman			if (strp == NULL)
4922708Swollman				return NULL;
4932708Swollman			*secsp += num;
4942708Swollman		}
4952708Swollman	}
4962708Swollman	return strp;
4972708Swollman}
4982708Swollman
4992708Swollman/*
5002708Swollman** Given a pointer into a time zone string, extract an offset, in
5012708Swollman** [+-]hh[:mm[:ss]] form, from the string.
5022708Swollman** If any error occurs, return NULL.
5032708Swollman** Otherwise, return a pointer to the first character not part of the time.
5042708Swollman*/
5052708Swollman
5062708Swollmanstatic const char *
5072708Swollmangetoffset(strp, offsetp)
5082708Swollmanregister const char *	strp;
5092708Swollmanlong * const		offsetp;
5102708Swollman{
5112708Swollman	register int	neg;
5122708Swollman
5132708Swollman	if (*strp == '-') {
5142708Swollman		neg = 1;
5152708Swollman		++strp;
5162708Swollman	} else if (isdigit(*strp) || *strp++ == '+')
5172708Swollman		neg = 0;
5182708Swollman	else	return NULL;		/* illegal offset */
5192708Swollman	strp = getsecs(strp, offsetp);
5202708Swollman	if (strp == NULL)
5212708Swollman		return NULL;		/* illegal time */
5222708Swollman	if (neg)
5232708Swollman		*offsetp = -*offsetp;
5242708Swollman	return strp;
5252708Swollman}
5262708Swollman
5272708Swollman/*
5282708Swollman** Given a pointer into a time zone string, extract a rule in the form
5292708Swollman** date[/time].  See POSIX section 8 for the format of "date" and "time".
5302708Swollman** If a valid rule is not found, return NULL.
5312708Swollman** Otherwise, return a pointer to the first character not part of the rule.
5322708Swollman*/
5332708Swollman
5342708Swollmanstatic const char *
5352708Swollmangetrule(strp, rulep)
5362708Swollmanconst char *			strp;
5372708Swollmanregister struct rule * const	rulep;
5382708Swollman{
5392708Swollman	if (*strp == 'J') {
5402708Swollman		/*
5412708Swollman		** Julian day.
5422708Swollman		*/
5432708Swollman		rulep->r_type = JULIAN_DAY;
5442708Swollman		++strp;
5452708Swollman		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
5462708Swollman	} else if (*strp == 'M') {
5472708Swollman		/*
5482708Swollman		** Month, week, day.
5492708Swollman		*/
5502708Swollman		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
5512708Swollman		++strp;
5522708Swollman		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
5532708Swollman		if (strp == NULL)
5542708Swollman			return NULL;
5552708Swollman		if (*strp++ != '.')
5562708Swollman			return NULL;
5572708Swollman		strp = getnum(strp, &rulep->r_week, 1, 5);
5582708Swollman		if (strp == NULL)
5592708Swollman			return NULL;
5602708Swollman		if (*strp++ != '.')
5612708Swollman			return NULL;
5622708Swollman		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
5632708Swollman	} else if (isdigit(*strp)) {
5642708Swollman		/*
5652708Swollman		** Day of year.
5662708Swollman		*/
5672708Swollman		rulep->r_type = DAY_OF_YEAR;
5682708Swollman		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
5692708Swollman	} else	return NULL;		/* invalid format */
5702708Swollman	if (strp == NULL)
5712708Swollman		return NULL;
5722708Swollman	if (*strp == '/') {
5732708Swollman		/*
5742708Swollman		** Time specified.
5752708Swollman		*/
5762708Swollman		++strp;
5772708Swollman		strp = getsecs(strp, &rulep->r_time);
5782708Swollman	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
5792708Swollman	return strp;
5802708Swollman}
5812708Swollman
5822708Swollman/*
5832708Swollman** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
5842708Swollman** year, a rule, and the offset from GMT at the time that rule takes effect,
5852708Swollman** calculate the Epoch-relative time that rule takes effect.
5862708Swollman*/
5872708Swollman
5882708Swollmanstatic time_t
5892708Swollmantranstime(janfirst, year, rulep, offset)
5902708Swollmanconst time_t				janfirst;
5912708Swollmanconst int				year;
5922708Swollmanregister const struct rule * const	rulep;
5932708Swollmanconst long				offset;
5942708Swollman{
5952708Swollman	register int	leapyear;
5962708Swollman	register time_t	value;
5972708Swollman	register int	i;
5982708Swollman	int		d, m1, yy0, yy1, yy2, dow;
5992708Swollman
6009936Swollman	INITIALIZE(value);
6012708Swollman	leapyear = isleap(year);
6022708Swollman	switch (rulep->r_type) {
6032708Swollman
6042708Swollman	case JULIAN_DAY:
6052708Swollman		/*
6062708Swollman		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
6072708Swollman		** years.
6082708Swollman		** In non-leap years, or if the day number is 59 or less, just
6092708Swollman		** add SECSPERDAY times the day number-1 to the time of
6102708Swollman		** January 1, midnight, to get the day.
6112708Swollman		*/
6122708Swollman		value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
6132708Swollman		if (leapyear && rulep->r_day >= 60)
6142708Swollman			value += SECSPERDAY;
6152708Swollman		break;
6162708Swollman
6172708Swollman	case DAY_OF_YEAR:
6182708Swollman		/*
6192708Swollman		** n - day of year.
6202708Swollman		** Just add SECSPERDAY times the day number to the time of
6212708Swollman		** January 1, midnight, to get the day.
6222708Swollman		*/
6232708Swollman		value = janfirst + rulep->r_day * SECSPERDAY;
6242708Swollman		break;
6252708Swollman
6262708Swollman	case MONTH_NTH_DAY_OF_WEEK:
6272708Swollman		/*
6282708Swollman		** Mm.n.d - nth "dth day" of month m.
6292708Swollman		*/
6302708Swollman		value = janfirst;
6312708Swollman		for (i = 0; i < rulep->r_mon - 1; ++i)
6322708Swollman			value += mon_lengths[leapyear][i] * SECSPERDAY;
6332708Swollman
6342708Swollman		/*
6352708Swollman		** Use Zeller's Congruence to get day-of-week of first day of
6362708Swollman		** month.
6372708Swollman		*/
6382708Swollman		m1 = (rulep->r_mon + 9) % 12 + 1;
6392708Swollman		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
6402708Swollman		yy1 = yy0 / 100;
6412708Swollman		yy2 = yy0 % 100;
6422708Swollman		dow = ((26 * m1 - 2) / 10 +
6432708Swollman			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
6442708Swollman		if (dow < 0)
6452708Swollman			dow += DAYSPERWEEK;
6462708Swollman
6472708Swollman		/*
6482708Swollman		** "dow" is the day-of-week of the first day of the month.  Get
6492708Swollman		** the day-of-month (zero-origin) of the first "dow" day of the
6502708Swollman		** month.
6512708Swollman		*/
6522708Swollman		d = rulep->r_day - dow;
6532708Swollman		if (d < 0)
6542708Swollman			d += DAYSPERWEEK;
6552708Swollman		for (i = 1; i < rulep->r_week; ++i) {
6562708Swollman			if (d + DAYSPERWEEK >=
6572708Swollman				mon_lengths[leapyear][rulep->r_mon - 1])
6582708Swollman					break;
6592708Swollman			d += DAYSPERWEEK;
6602708Swollman		}
6612708Swollman
6622708Swollman		/*
6632708Swollman		** "d" is the day-of-month (zero-origin) of the day we want.
6642708Swollman		*/
6652708Swollman		value += d * SECSPERDAY;
6662708Swollman		break;
6672708Swollman	}
6682708Swollman
6692708Swollman	/*
6702708Swollman	** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
6712708Swollman	** question.  To get the Epoch-relative time of the specified local
6722708Swollman	** time on that day, add the transition time and the current offset
6732708Swollman	** from GMT.
6742708Swollman	*/
6752708Swollman	return value + rulep->r_time + offset;
6762708Swollman}
6772708Swollman
6782708Swollman/*
6792708Swollman** Given a POSIX section 8-style TZ string, fill in the rule tables as
6802708Swollman** appropriate.
6812708Swollman*/
6822708Swollman
6832708Swollmanstatic int
6842708Swollmantzparse(name, sp, lastditch)
6852708Swollmanconst char *			name;
6862708Swollmanregister struct state * const	sp;
6872708Swollmanconst int			lastditch;
6882708Swollman{
6892708Swollman	const char *			stdname;
6902708Swollman	const char *			dstname;
6919936Swollman	size_t				stdlen;
6929936Swollman	size_t				dstlen;
6932708Swollman	long				stdoffset;
6942708Swollman	long				dstoffset;
6952708Swollman	register time_t *		atp;
6962708Swollman	register unsigned char *	typep;
6972708Swollman	register char *			cp;
6982708Swollman	register int			load_result;
6992708Swollman
7009936Swollman	INITIALIZE(dstname);
7012708Swollman	stdname = name;
7022708Swollman	if (lastditch) {
7032708Swollman		stdlen = strlen(name);	/* length of standard zone name */
7042708Swollman		name += stdlen;
7052708Swollman		if (stdlen >= sizeof sp->chars)
7062708Swollman			stdlen = (sizeof sp->chars) - 1;
7072708Swollman	} else {
7082708Swollman		name = getzname(name);
7092708Swollman		stdlen = name - stdname;
7102708Swollman		if (stdlen < 3)
7112708Swollman			return -1;
7122708Swollman	}
7132708Swollman	if (*name == '\0')
7142708Swollman		return -1;	/* was "stdoffset = 0;" */
7152708Swollman	else {
7162708Swollman		name = getoffset(name, &stdoffset);
7172708Swollman		if (name == NULL)
7182708Swollman			return -1;
7192708Swollman	}
7202708Swollman	load_result = tzload(TZDEFRULES, sp);
7212708Swollman	if (load_result != 0)
7222708Swollman		sp->leapcnt = 0;		/* so, we're off a little */
7232708Swollman	if (*name != '\0') {
7242708Swollman		dstname = name;
7252708Swollman		name = getzname(name);
7262708Swollman		dstlen = name - dstname;	/* length of DST zone name */
7272708Swollman		if (dstlen < 3)
7282708Swollman			return -1;
7292708Swollman		if (*name != '\0' && *name != ',' && *name != ';') {
7302708Swollman			name = getoffset(name, &dstoffset);
7312708Swollman			if (name == NULL)
7322708Swollman				return -1;
7332708Swollman		} else	dstoffset = stdoffset - SECSPERHOUR;
7342708Swollman		if (*name == ',' || *name == ';') {
7352708Swollman			struct rule	start;
7362708Swollman			struct rule	end;
7372708Swollman			register int	year;
7382708Swollman			register time_t	janfirst;
7392708Swollman			time_t		starttime;
7402708Swollman			time_t		endtime;
7412708Swollman
7422708Swollman			++name;
7432708Swollman			if ((name = getrule(name, &start)) == NULL)
7442708Swollman				return -1;
7452708Swollman			if (*name++ != ',')
7462708Swollman				return -1;
7472708Swollman			if ((name = getrule(name, &end)) == NULL)
7482708Swollman				return -1;
7492708Swollman			if (*name != '\0')
7502708Swollman				return -1;
7512708Swollman			sp->typecnt = 2;	/* standard time and DST */
7522708Swollman			/*
7532708Swollman			** Two transitions per year, from EPOCH_YEAR to 2037.
7542708Swollman			*/
7552708Swollman			sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
7562708Swollman			if (sp->timecnt > TZ_MAX_TIMES)
7572708Swollman				return -1;
7582708Swollman			sp->ttis[0].tt_gmtoff = -dstoffset;
7592708Swollman			sp->ttis[0].tt_isdst = 1;
7602708Swollman			sp->ttis[0].tt_abbrind = stdlen + 1;
7612708Swollman			sp->ttis[1].tt_gmtoff = -stdoffset;
7622708Swollman			sp->ttis[1].tt_isdst = 0;
7632708Swollman			sp->ttis[1].tt_abbrind = 0;
7642708Swollman			atp = sp->ats;
7652708Swollman			typep = sp->types;
7662708Swollman			janfirst = 0;
7672708Swollman			for (year = EPOCH_YEAR; year <= 2037; ++year) {
7682708Swollman				starttime = transtime(janfirst, year, &start,
7692708Swollman					stdoffset);
7702708Swollman				endtime = transtime(janfirst, year, &end,
7712708Swollman					dstoffset);
7722708Swollman				if (starttime > endtime) {
7732708Swollman					*atp++ = endtime;
7742708Swollman					*typep++ = 1;	/* DST ends */
7752708Swollman					*atp++ = starttime;
7762708Swollman					*typep++ = 0;	/* DST begins */
7772708Swollman				} else {
7782708Swollman					*atp++ = starttime;
7792708Swollman					*typep++ = 0;	/* DST begins */
7802708Swollman					*atp++ = endtime;
7812708Swollman					*typep++ = 1;	/* DST ends */
7822708Swollman				}
7832708Swollman				janfirst += year_lengths[isleap(year)] *
7842708Swollman					SECSPERDAY;
7852708Swollman			}
7862708Swollman		} else {
7879936Swollman			register long	theirstdoffset;
7889936Swollman			register long	theirdstoffset;
7899936Swollman			register long	theiroffset;
7909936Swollman			register int	isdst;
7912708Swollman			register int	i;
7929936Swollman			register int	j;
7932708Swollman
7942708Swollman			if (*name != '\0')
7952708Swollman				return -1;
7962708Swollman			if (load_result != 0)
7972708Swollman				return -1;
7982708Swollman			/*
7999936Swollman			** Initial values of theirstdoffset and theirdstoffset.
8002708Swollman			*/
8019936Swollman			theirstdoffset = 0;
8029936Swollman			for (i = 0; i < sp->timecnt; ++i) {
8039936Swollman				j = sp->types[i];
8049936Swollman				if (!sp->ttis[j].tt_isdst) {
8059936Swollman					theirstdoffset = -sp->ttis[j].tt_gmtoff;
8069936Swollman					break;
8072708Swollman				}
8082708Swollman			}
8099936Swollman			theirdstoffset = 0;
8109936Swollman			for (i = 0; i < sp->timecnt; ++i) {
8119936Swollman				j = sp->types[i];
8129936Swollman				if (sp->ttis[j].tt_isdst) {
8139936Swollman					theirdstoffset = -sp->ttis[j].tt_gmtoff;
8149936Swollman					break;
8159936Swollman				}
8169936Swollman			}
8172708Swollman			/*
8189936Swollman			** Initially we're assumed to be in standard time.
8192708Swollman			*/
8209936Swollman			isdst = FALSE;
8219936Swollman			theiroffset = theirstdoffset;
8222708Swollman			/*
8239936Swollman			** Now juggle transition times and types
8249936Swollman			** tracking offsets as you do.
8252708Swollman			*/
8262708Swollman			for (i = 0; i < sp->timecnt; ++i) {
8279936Swollman				j = sp->types[i];
8289936Swollman				sp->types[i] = sp->ttis[j].tt_isdst;
8299936Swollman				if (sp->ttis[j].tt_ttisgmt) {
8309936Swollman					/* No adjustment to transition time */
8319936Swollman				} else {
8329936Swollman					/*
8339936Swollman					** If summer time is in effect, and the
8349936Swollman					** transition time was not specified as
8359936Swollman					** standard time, add the summer time
8369936Swollman					** offset to the transition time;
8379936Swollman					** otherwise, add the standard time
8389936Swollman					** offset to the transition time.
8399936Swollman					*/
8409936Swollman					/*
8419936Swollman					** Transitions from DST to DDST
8429936Swollman					** will effectively disappear since
8439936Swollman					** POSIX provides for only one DST
8449936Swollman					** offset.
8459936Swollman					*/
8469936Swollman					if (isdst && !sp->ttis[j].tt_ttisstd) {
8479936Swollman						sp->ats[i] += dstoffset -
8489936Swollman							theirdstoffset;
8499936Swollman					} else {
8509936Swollman						sp->ats[i] += stdoffset -
8519936Swollman							theirstdoffset;
8529936Swollman					}
8539936Swollman				}
8549936Swollman				theiroffset = -sp->ttis[j].tt_gmtoff;
8559936Swollman				if (sp->ttis[j].tt_isdst)
8569936Swollman					theirdstoffset = theiroffset;
8579936Swollman				else	theirstdoffset = theiroffset;
8582708Swollman			}
8599936Swollman			/*
8609936Swollman			** Finally, fill in ttis.
8619936Swollman			** ttisstd and ttisgmt need not be handled.
8629936Swollman			*/
8639936Swollman			sp->ttis[0].tt_gmtoff = -stdoffset;
8649936Swollman			sp->ttis[0].tt_isdst = FALSE;
8659936Swollman			sp->ttis[0].tt_abbrind = 0;
8669936Swollman			sp->ttis[1].tt_gmtoff = -dstoffset;
8679936Swollman			sp->ttis[1].tt_isdst = TRUE;
8689936Swollman			sp->ttis[1].tt_abbrind = stdlen + 1;
8692708Swollman		}
8702708Swollman	} else {
8712708Swollman		dstlen = 0;
8722708Swollman		sp->typecnt = 1;		/* only standard time */
8732708Swollman		sp->timecnt = 0;
8742708Swollman		sp->ttis[0].tt_gmtoff = -stdoffset;
8752708Swollman		sp->ttis[0].tt_isdst = 0;
8762708Swollman		sp->ttis[0].tt_abbrind = 0;
8772708Swollman	}
8782708Swollman	sp->charcnt = stdlen + 1;
8792708Swollman	if (dstlen != 0)
8802708Swollman		sp->charcnt += dstlen + 1;
8812708Swollman	if (sp->charcnt > sizeof sp->chars)
8822708Swollman		return -1;
8832708Swollman	cp = sp->chars;
8842708Swollman	(void) strncpy(cp, stdname, stdlen);
8852708Swollman	cp += stdlen;
8862708Swollman	*cp++ = '\0';
8872708Swollman	if (dstlen != 0) {
8882708Swollman		(void) strncpy(cp, dstname, dstlen);
8892708Swollman		*(cp + dstlen) = '\0';
8902708Swollman	}
8912708Swollman	return 0;
8922708Swollman}
8932708Swollman
8942708Swollmanstatic void
8952708Swollmangmtload(sp)
8962708Swollmanstruct state * const	sp;
8972708Swollman{
8989936Swollman	if (tzload(gmt, sp) != 0)
8999936Swollman		(void) tzparse(gmt, sp, TRUE);
9002708Swollman}
9012708Swollman
9022708Swollman#ifndef STD_INSPIRED
9039936Swollman/*
9049936Swollman** A non-static declaration of tzsetwall in a system header file
9059936Swollman** may cause a warning about this upcoming static declaration...
9069936Swollman*/
9072708Swollmanstatic
9082708Swollman#endif /* !defined STD_INSPIRED */
9092708Swollmanvoid
9109936Swollmantzsetwall P((void))
9112708Swollman{
9129936Swollman	if (lcl_is_set < 0)
9139936Swollman		return;
9149936Swollman	lcl_is_set = -1;
9159936Swollman
9162708Swollman#ifdef ALL_STATE
9172708Swollman	if (lclptr == NULL) {
9182708Swollman		lclptr = (struct state *) malloc(sizeof *lclptr);
9192708Swollman		if (lclptr == NULL) {
9202708Swollman			settzname();	/* all we can do */
9212708Swollman			return;
9222708Swollman		}
9232708Swollman	}
9242708Swollman#endif /* defined ALL_STATE */
9252708Swollman	if (tzload((char *) NULL, lclptr) != 0)
9262708Swollman		gmtload(lclptr);
9272708Swollman	settzname();
9282708Swollman}
9292708Swollman
9302708Swollmanvoid
9319936Swollmantzset P((void))
9322708Swollman{
9332708Swollman	register const char *	name;
9342708Swollman
9352708Swollman	name = getenv("TZ");
9362708Swollman	if (name == NULL) {
9372708Swollman		tzsetwall();
9382708Swollman		return;
9392708Swollman	}
9409936Swollman
9419936Swollman	if (lcl_is_set > 0  &&  strcmp(lcl_TZname, name) == 0)
9429936Swollman		return;
9439936Swollman	lcl_is_set = (strlen(name) < sizeof(lcl_TZname));
9449936Swollman	if (lcl_is_set)
9459936Swollman		(void) strcpy(lcl_TZname, name);
9469936Swollman
9472708Swollman#ifdef ALL_STATE
9482708Swollman	if (lclptr == NULL) {
9492708Swollman		lclptr = (struct state *) malloc(sizeof *lclptr);
9502708Swollman		if (lclptr == NULL) {
9512708Swollman			settzname();	/* all we can do */
9522708Swollman			return;
9532708Swollman		}
9542708Swollman	}
9552708Swollman#endif /* defined ALL_STATE */
9562708Swollman	if (*name == '\0') {
9572708Swollman		/*
9582708Swollman		** User wants it fast rather than right.
9592708Swollman		*/
9602708Swollman		lclptr->leapcnt = 0;		/* so, we're off a little */
9612708Swollman		lclptr->timecnt = 0;
9622708Swollman		lclptr->ttis[0].tt_gmtoff = 0;
9632708Swollman		lclptr->ttis[0].tt_abbrind = 0;
9649936Swollman		(void) strcpy(lclptr->chars, gmt);
9652708Swollman	} else if (tzload(name, lclptr) != 0)
9662708Swollman		if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
9672708Swollman			(void) gmtload(lclptr);
9682708Swollman	settzname();
9692708Swollman}
9702708Swollman
9712708Swollman/*
9722708Swollman** The easy way to behave "as if no library function calls" localtime
9732708Swollman** is to not call it--so we drop its guts into "localsub", which can be
9742708Swollman** freely called.  (And no, the PANS doesn't require the above behavior--
9752708Swollman** but it *is* desirable.)
9762708Swollman**
9772708Swollman** The unused offset argument is for the benefit of mktime variants.
9782708Swollman*/
9792708Swollman
9802708Swollman/*ARGSUSED*/
9812708Swollmanstatic void
9822708Swollmanlocalsub(timep, offset, tmp)
9832708Swollmanconst time_t * const	timep;
9842708Swollmanconst long		offset;
9852708Swollmanstruct tm * const	tmp;
9862708Swollman{
9879936Swollman	register struct state *		sp;
9882708Swollman	register const struct ttinfo *	ttisp;
9892708Swollman	register int			i;
9902708Swollman	const time_t			t = *timep;
9912708Swollman
9922708Swollman	sp = lclptr;
9932708Swollman#ifdef ALL_STATE
9942708Swollman	if (sp == NULL) {
9952708Swollman		gmtsub(timep, offset, tmp);
9962708Swollman		return;
9972708Swollman	}
9982708Swollman#endif /* defined ALL_STATE */
9992708Swollman	if (sp->timecnt == 0 || t < sp->ats[0]) {
10002708Swollman		i = 0;
10012708Swollman		while (sp->ttis[i].tt_isdst)
10022708Swollman			if (++i >= sp->typecnt) {
10032708Swollman				i = 0;
10042708Swollman				break;
10052708Swollman			}
10062708Swollman	} else {
10072708Swollman		for (i = 1; i < sp->timecnt; ++i)
10082708Swollman			if (t < sp->ats[i])
10092708Swollman				break;
10102708Swollman		i = sp->types[i - 1];
10112708Swollman	}
10122708Swollman	ttisp = &sp->ttis[i];
10132708Swollman	/*
10142708Swollman	** To get (wrong) behavior that's compatible with System V Release 2.0
10152708Swollman	** you'd replace the statement below with
10162708Swollman	**	t += ttisp->tt_gmtoff;
10172708Swollman	**	timesub(&t, 0L, sp, tmp);
10182708Swollman	*/
10192708Swollman	timesub(&t, ttisp->tt_gmtoff, sp, tmp);
10202708Swollman	tmp->tm_isdst = ttisp->tt_isdst;
10219936Swollman	tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
10222708Swollman#ifdef TM_ZONE
10239936Swollman	tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
10242708Swollman#endif /* defined TM_ZONE */
10252708Swollman}
10262708Swollman
10272708Swollmanstruct tm *
10282708Swollmanlocaltime(timep)
10292708Swollmanconst time_t * const	timep;
10302708Swollman{
10319936Swollman	tzset();
10322708Swollman	localsub(timep, 0L, &tm);
10332708Swollman	return &tm;
10342708Swollman}
10352708Swollman
10362708Swollman/*
10372708Swollman** gmtsub is to gmtime as localsub is to localtime.
10382708Swollman*/
10392708Swollman
10402708Swollmanstatic void
10412708Swollmangmtsub(timep, offset, tmp)
10422708Swollmanconst time_t * const	timep;
10432708Swollmanconst long		offset;
10442708Swollmanstruct tm * const	tmp;
10452708Swollman{
10462708Swollman	if (!gmt_is_set) {
10472708Swollman		gmt_is_set = TRUE;
10482708Swollman#ifdef ALL_STATE
10492708Swollman		gmtptr = (struct state *) malloc(sizeof *gmtptr);
10502708Swollman		if (gmtptr != NULL)
10512708Swollman#endif /* defined ALL_STATE */
10522708Swollman			gmtload(gmtptr);
10532708Swollman	}
10542708Swollman	timesub(timep, offset, gmtptr, tmp);
10552708Swollman#ifdef TM_ZONE
10562708Swollman	/*
10572708Swollman	** Could get fancy here and deliver something such as
10582708Swollman	** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
10592708Swollman	** but this is no time for a treasure hunt.
10602708Swollman	*/
10612708Swollman	if (offset != 0)
10629936Swollman		tmp->TM_ZONE = wildabbr;
10632708Swollman	else {
10642708Swollman#ifdef ALL_STATE
10652708Swollman		if (gmtptr == NULL)
10669936Swollman			tmp->TM_ZONE = gmt;
10672708Swollman		else	tmp->TM_ZONE = gmtptr->chars;
10682708Swollman#endif /* defined ALL_STATE */
10692708Swollman#ifndef ALL_STATE
10702708Swollman		tmp->TM_ZONE = gmtptr->chars;
10712708Swollman#endif /* State Farm */
10722708Swollman	}
10732708Swollman#endif /* defined TM_ZONE */
10742708Swollman}
10752708Swollman
10762708Swollmanstruct tm *
10772708Swollmangmtime(timep)
10782708Swollmanconst time_t * const	timep;
10792708Swollman{
10802708Swollman	gmtsub(timep, 0L, &tm);
10812708Swollman	return &tm;
10822708Swollman}
10832708Swollman
10842708Swollman#ifdef STD_INSPIRED
10852708Swollman
10862708Swollmanstruct tm *
10872708Swollmanofftime(timep, offset)
10882708Swollmanconst time_t * const	timep;
10892708Swollmanconst long		offset;
10902708Swollman{
10912708Swollman	gmtsub(timep, offset, &tm);
10922708Swollman	return &tm;
10932708Swollman}
10942708Swollman
10952708Swollman#endif /* defined STD_INSPIRED */
10962708Swollman
10972708Swollmanstatic void
10982708Swollmantimesub(timep, offset, sp, tmp)
10992708Swollmanconst time_t * const			timep;
11002708Swollmanconst long				offset;
11012708Swollmanregister const struct state * const	sp;
11022708Swollmanregister struct tm * const		tmp;
11032708Swollman{
11042708Swollman	register const struct lsinfo *	lp;
11052708Swollman	register long			days;
11062708Swollman	register long			rem;
11072708Swollman	register int			y;
11082708Swollman	register int			yleap;
11092708Swollman	register const int *		ip;
11102708Swollman	register long			corr;
11112708Swollman	register int			hit;
11122708Swollman	register int			i;
11132708Swollman
11142708Swollman	corr = 0;
11152708Swollman	hit = 0;
11162708Swollman#ifdef ALL_STATE
11172708Swollman	i = (sp == NULL) ? 0 : sp->leapcnt;
11182708Swollman#endif /* defined ALL_STATE */
11192708Swollman#ifndef ALL_STATE
11202708Swollman	i = sp->leapcnt;
11212708Swollman#endif /* State Farm */
11222708Swollman	while (--i >= 0) {
11232708Swollman		lp = &sp->lsis[i];
11242708Swollman		if (*timep >= lp->ls_trans) {
11252708Swollman			if (*timep == lp->ls_trans) {
11262708Swollman				hit = ((i == 0 && lp->ls_corr > 0) ||
11272708Swollman					lp->ls_corr > sp->lsis[i - 1].ls_corr);
11282708Swollman				if (hit)
11292708Swollman					while (i > 0 &&
11302708Swollman						sp->lsis[i].ls_trans ==
11312708Swollman						sp->lsis[i - 1].ls_trans + 1 &&
11322708Swollman						sp->lsis[i].ls_corr ==
11332708Swollman						sp->lsis[i - 1].ls_corr + 1) {
11342708Swollman							++hit;
11352708Swollman							--i;
11362708Swollman					}
11372708Swollman			}
11382708Swollman			corr = lp->ls_corr;
11392708Swollman			break;
11402708Swollman		}
11412708Swollman	}
11422708Swollman	days = *timep / SECSPERDAY;
11432708Swollman	rem = *timep % SECSPERDAY;
11442708Swollman#ifdef mc68k
11452708Swollman	if (*timep == 0x80000000) {
11462708Swollman		/*
11472708Swollman		** A 3B1 muffs the division on the most negative number.
11482708Swollman		*/
11492708Swollman		days = -24855;
11502708Swollman		rem = -11648;
11512708Swollman	}
11529936Swollman#endif /* defined mc68k */
11532708Swollman	rem += (offset - corr);
11542708Swollman	while (rem < 0) {
11552708Swollman		rem += SECSPERDAY;
11562708Swollman		--days;
11572708Swollman	}
11582708Swollman	while (rem >= SECSPERDAY) {
11592708Swollman		rem -= SECSPERDAY;
11602708Swollman		++days;
11612708Swollman	}
11622708Swollman	tmp->tm_hour = (int) (rem / SECSPERHOUR);
11632708Swollman	rem = rem % SECSPERHOUR;
11642708Swollman	tmp->tm_min = (int) (rem / SECSPERMIN);
11652708Swollman	tmp->tm_sec = (int) (rem % SECSPERMIN);
11662708Swollman	if (hit)
11672708Swollman		/*
11682708Swollman		** A positive leap second requires a special
11692708Swollman		** representation.  This uses "... ??:59:60" et seq.
11702708Swollman		*/
11712708Swollman		tmp->tm_sec += hit;
11722708Swollman	tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
11732708Swollman	if (tmp->tm_wday < 0)
11742708Swollman		tmp->tm_wday += DAYSPERWEEK;
11752708Swollman	y = EPOCH_YEAR;
11762708Swollman	if (days >= 0)
11772708Swollman		for ( ; ; ) {
11782708Swollman			yleap = isleap(y);
11792708Swollman			if (days < (long) year_lengths[yleap])
11802708Swollman				break;
11812708Swollman			++y;
11822708Swollman			days = days - (long) year_lengths[yleap];
11832708Swollman		}
11842708Swollman	else do {
11852708Swollman		--y;
11862708Swollman		yleap = isleap(y);
11872708Swollman		days = days + (long) year_lengths[yleap];
11882708Swollman	} while (days < 0);
11892708Swollman	tmp->tm_year = y - TM_YEAR_BASE;
11902708Swollman	tmp->tm_yday = (int) days;
11912708Swollman	ip = mon_lengths[yleap];
11922708Swollman	for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
11932708Swollman		days = days - (long) ip[tmp->tm_mon];
11942708Swollman	tmp->tm_mday = (int) (days + 1);
11952708Swollman	tmp->tm_isdst = 0;
11962708Swollman#ifdef TM_GMTOFF
11972708Swollman	tmp->TM_GMTOFF = offset;
11982708Swollman#endif /* defined TM_GMTOFF */
11992708Swollman}
12002708Swollman
12012708Swollmanchar *
12022708Swollmanctime(timep)
12032708Swollmanconst time_t * const	timep;
12042708Swollman{
12059936Swollman/*
12069936Swollman** Section 4.12.3.2 of X3.159-1989 requires that
12079936Swollman**	The ctime funciton converts the calendar time pointed to by timer
12089936Swollman**	to local time in the form of a string.  It is equivalent to
12099936Swollman**		asctime(localtime(timer))
12109936Swollman*/
12112708Swollman	return asctime(localtime(timep));
12122708Swollman}
12132708Swollman
12142708Swollman/*
12152708Swollman** Adapted from code provided by Robert Elz, who writes:
12162708Swollman**	The "best" way to do mktime I think is based on an idea of Bob
12172708Swollman**	Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
12182708Swollman**	It does a binary search of the time_t space.  Since time_t's are
12192708Swollman**	just 32 bits, its a max of 32 iterations (even at 64 bits it
12202708Swollman**	would still be very reasonable).
12212708Swollman*/
12222708Swollman
12232708Swollman#ifndef WRONG
12242708Swollman#define WRONG	(-1)
12252708Swollman#endif /* !defined WRONG */
12262708Swollman
12272708Swollman/*
12282708Swollman** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
12292708Swollman*/
12302708Swollman
12312708Swollmanstatic int
12322708Swollmanincrement_overflow(number, delta)
12332708Swollmanint *	number;
12342708Swollmanint	delta;
12352708Swollman{
12369936Swollman	int	number0;
12378870Srgrimes
12382708Swollman	number0 = *number;
12392708Swollman	*number += delta;
12402708Swollman	return (*number < number0) != (delta < 0);
12412708Swollman}
12422708Swollman
12432708Swollmanstatic int
12442708Swollmannormalize_overflow(tensptr, unitsptr, base)
12452708Swollmanint * const	tensptr;
12462708Swollmanint * const	unitsptr;
12472708Swollmanconst int	base;
12482708Swollman{
12492708Swollman	register int	tensdelta;
12502708Swollman
12512708Swollman	tensdelta = (*unitsptr >= 0) ?
12522708Swollman		(*unitsptr / base) :
12532708Swollman		(-1 - (-1 - *unitsptr) / base);
12542708Swollman	*unitsptr -= tensdelta * base;
12552708Swollman	return increment_overflow(tensptr, tensdelta);
12562708Swollman}
12572708Swollman
12582708Swollmanstatic int
12592708Swollmantmcomp(atmp, btmp)
12602708Swollmanregister const struct tm * const atmp;
12612708Swollmanregister const struct tm * const btmp;
12622708Swollman{
12632708Swollman	register int	result;
12642708Swollman
12652708Swollman	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
12662708Swollman		(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
12672708Swollman		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
12682708Swollman		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
12692708Swollman		(result = (atmp->tm_min - btmp->tm_min)) == 0)
12702708Swollman			result = atmp->tm_sec - btmp->tm_sec;
12712708Swollman	return result;
12722708Swollman}
12732708Swollman
12742708Swollmanstatic time_t
12752708Swollmantime2(tmp, funcp, offset, okayp)
12762708Swollmanstruct tm * const	tmp;
12779936Swollmanvoid (* const		funcp) P((const time_t*, long, struct tm*));
12782708Swollmanconst long		offset;
12792708Swollmanint * const		okayp;
12802708Swollman{
12812708Swollman	register const struct state *	sp;
12822708Swollman	register int			dir;
12832708Swollman	register int			bits;
12842708Swollman	register int			i, j ;
12852708Swollman	register int			saved_seconds;
12862708Swollman	time_t				newt;
12872708Swollman	time_t				t;
12882708Swollman	struct tm			yourtm, mytm;
12892708Swollman
12902708Swollman	*okayp = FALSE;
12912708Swollman	yourtm = *tmp;
12922708Swollman	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
12932708Swollman		return WRONG;
12942708Swollman	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
12952708Swollman		return WRONG;
12962708Swollman	if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
12972708Swollman		return WRONG;
12982708Swollman	/*
12992708Swollman	** Turn yourtm.tm_year into an actual year number for now.
13002708Swollman	** It is converted back to an offset from TM_YEAR_BASE later.
13012708Swollman	*/
13022708Swollman	if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
13032708Swollman		return WRONG;
13042708Swollman	while (yourtm.tm_mday <= 0) {
13052708Swollman		if (increment_overflow(&yourtm.tm_year, -1))
13062708Swollman			return WRONG;
13072708Swollman		yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)];
13082708Swollman	}
13092708Swollman	while (yourtm.tm_mday > DAYSPERLYEAR) {
13102708Swollman		yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)];
13112708Swollman		if (increment_overflow(&yourtm.tm_year, 1))
13122708Swollman			return WRONG;
13132708Swollman	}
13142708Swollman	for ( ; ; ) {
13152708Swollman		i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
13162708Swollman		if (yourtm.tm_mday <= i)
13172708Swollman			break;
13182708Swollman		yourtm.tm_mday -= i;
13192708Swollman		if (++yourtm.tm_mon >= MONSPERYEAR) {
13202708Swollman			yourtm.tm_mon = 0;
13212708Swollman			if (increment_overflow(&yourtm.tm_year, 1))
13222708Swollman				return WRONG;
13232708Swollman		}
13242708Swollman	}
13252708Swollman	if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
13262708Swollman		return WRONG;
13272708Swollman	if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
13282708Swollman		/*
13292708Swollman		** We can't set tm_sec to 0, because that might push the
13302708Swollman		** time below the minimum representable time.
13312708Swollman		** Set tm_sec to 59 instead.
13322708Swollman		** This assumes that the minimum representable time is
13332708Swollman		** not in the same minute that a leap second was deleted from,
13342708Swollman		** which is a safer assumption than using 58 would be.
13352708Swollman		*/
13362708Swollman		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
13372708Swollman			return WRONG;
13382708Swollman		saved_seconds = yourtm.tm_sec;
13392708Swollman		yourtm.tm_sec = SECSPERMIN - 1;
13402708Swollman	} else {
13412708Swollman		saved_seconds = yourtm.tm_sec;
13422708Swollman		yourtm.tm_sec = 0;
13432708Swollman	}
13442708Swollman	/*
13452708Swollman	** Calculate the number of magnitude bits in a time_t
13462708Swollman	** (this works regardless of whether time_t is
13472708Swollman	** signed or unsigned, though lint complains if unsigned).
13482708Swollman	*/
13492708Swollman	for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
13502708Swollman		continue;
13512708Swollman	/*
13522708Swollman	** If time_t is signed, then 0 is the median value,
13532708Swollman	** if time_t is unsigned, then 1 << bits is median.
13542708Swollman	*/
13552708Swollman	t = (t < 0) ? 0 : ((time_t) 1 << bits);
13562708Swollman	for ( ; ; ) {
13572708Swollman		(*funcp)(&t, offset, &mytm);
13582708Swollman		dir = tmcomp(&mytm, &yourtm);
13592708Swollman		if (dir != 0) {
13602708Swollman			if (bits-- < 0)
13612708Swollman				return WRONG;
13622708Swollman			if (bits < 0)
13632708Swollman				--t;
13642708Swollman			else if (dir > 0)
13652708Swollman				t -= (time_t) 1 << bits;
13662708Swollman			else	t += (time_t) 1 << bits;
13672708Swollman			continue;
13682708Swollman		}
13692708Swollman		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
13702708Swollman			break;
13712708Swollman		/*
13722708Swollman		** Right time, wrong type.
13732708Swollman		** Hunt for right time, right type.
13742708Swollman		** It's okay to guess wrong since the guess
13752708Swollman		** gets checked.
13762708Swollman		*/
13772708Swollman		/*
13782708Swollman		** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
13792708Swollman		*/
13802708Swollman		sp = (const struct state *)
13812708Swollman			(((void *) funcp == (void *) localsub) ?
13822708Swollman			lclptr : gmtptr);
13832708Swollman#ifdef ALL_STATE
13842708Swollman		if (sp == NULL)
13852708Swollman			return WRONG;
13862708Swollman#endif /* defined ALL_STATE */
13872708Swollman		for (i = 0; i < sp->typecnt; ++i) {
13882708Swollman			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
13892708Swollman				continue;
13902708Swollman			for (j = 0; j < sp->typecnt; ++j) {
13912708Swollman				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
13922708Swollman					continue;
13932708Swollman				newt = t + sp->ttis[j].tt_gmtoff -
13942708Swollman					sp->ttis[i].tt_gmtoff;
13952708Swollman				(*funcp)(&newt, offset, &mytm);
13962708Swollman				if (tmcomp(&mytm, &yourtm) != 0)
13972708Swollman					continue;
13982708Swollman				if (mytm.tm_isdst != yourtm.tm_isdst)
13992708Swollman					continue;
14002708Swollman				/*
14012708Swollman				** We have a match.
14022708Swollman				*/
14032708Swollman				t = newt;
14042708Swollman				goto label;
14052708Swollman			}
14062708Swollman		}
14072708Swollman		return WRONG;
14082708Swollman	}
14092708Swollmanlabel:
14102708Swollman	newt = t + saved_seconds;
14112708Swollman	if ((newt < t) != (saved_seconds < 0))
14122708Swollman		return WRONG;
14132708Swollman	t = newt;
14142708Swollman	(*funcp)(&t, offset, tmp);
14152708Swollman	*okayp = TRUE;
14162708Swollman	return t;
14172708Swollman}
14182708Swollman
14192708Swollmanstatic time_t
14202708Swollmantime1(tmp, funcp, offset)
14212708Swollmanstruct tm * const	tmp;
14229936Swollmanvoid (* const		funcp) P((const time_t*, long, struct tm*));
14232708Swollmanconst long		offset;
14242708Swollman{
14252708Swollman	register time_t			t;
14262708Swollman	register const struct state *	sp;
14272708Swollman	register int			samei, otheri;
14282708Swollman	int				okay;
14292708Swollman
14302708Swollman	if (tmp->tm_isdst > 1)
14312708Swollman		tmp->tm_isdst = 1;
14322708Swollman	t = time2(tmp, funcp, offset, &okay);
14332708Swollman#ifdef PCTS
14342708Swollman	/*
14352708Swollman	** PCTS code courtesy Grant Sullivan (grant@osf.org).
14362708Swollman	*/
14372708Swollman	if (okay)
14382708Swollman		return t;
14392708Swollman	if (tmp->tm_isdst < 0)
14402708Swollman		tmp->tm_isdst = 0;	/* reset to std and try again */
14412708Swollman#endif /* defined PCTS */
14422708Swollman#ifndef PCTS
14432708Swollman	if (okay || tmp->tm_isdst < 0)
14442708Swollman		return t;
14452708Swollman#endif /* !defined PCTS */
14462708Swollman	/*
14472708Swollman	** We're supposed to assume that somebody took a time of one type
14482708Swollman	** and did some math on it that yielded a "struct tm" that's bad.
14492708Swollman	** We try to divine the type they started from and adjust to the
14502708Swollman	** type they need.
14512708Swollman	*/
14522708Swollman	/*
14532708Swollman	** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
14542708Swollman	*/
14552708Swollman	sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
14562708Swollman		lclptr : gmtptr);
14572708Swollman#ifdef ALL_STATE
14582708Swollman	if (sp == NULL)
14592708Swollman		return WRONG;
14602708Swollman#endif /* defined ALL_STATE */
14612708Swollman	for (samei = 0; samei < sp->typecnt; ++samei) {
14622708Swollman		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
14632708Swollman			continue;
14642708Swollman		for (otheri = 0; otheri < sp->typecnt; ++otheri) {
14652708Swollman			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
14662708Swollman				continue;
14672708Swollman			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
14682708Swollman					sp->ttis[samei].tt_gmtoff;
14692708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
14702708Swollman			t = time2(tmp, funcp, offset, &okay);
14712708Swollman			if (okay)
14722708Swollman				return t;
14732708Swollman			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
14742708Swollman					sp->ttis[samei].tt_gmtoff;
14752708Swollman			tmp->tm_isdst = !tmp->tm_isdst;
14762708Swollman		}
14772708Swollman	}
14782708Swollman	return WRONG;
14792708Swollman}
14802708Swollman
14812708Swollmantime_t
14822708Swollmanmktime(tmp)
14832708Swollmanstruct tm * const	tmp;
14842708Swollman{
14859936Swollman	tzset();
14862708Swollman	return time1(tmp, localsub, 0L);
14872708Swollman}
14882708Swollman
14892708Swollman#ifdef STD_INSPIRED
14902708Swollman
14912708Swollmantime_t
14922708Swollmantimelocal(tmp)
14932708Swollmanstruct tm * const	tmp;
14942708Swollman{
14952708Swollman	tmp->tm_isdst = -1;	/* in case it wasn't initialized */
14962708Swollman	return mktime(tmp);
14972708Swollman}
14982708Swollman
14992708Swollmantime_t
15002708Swollmantimegm(tmp)
15012708Swollmanstruct tm * const	tmp;
15022708Swollman{
15032708Swollman	tmp->tm_isdst = 0;
15042708Swollman	return time1(tmp, gmtsub, 0L);
15052708Swollman}
15062708Swollman
15072708Swollmantime_t
15082708Swollmantimeoff(tmp, offset)
15092708Swollmanstruct tm * const	tmp;
15102708Swollmanconst long		offset;
15112708Swollman{
15122708Swollman	tmp->tm_isdst = 0;
15132708Swollman	return time1(tmp, gmtsub, offset);
15142708Swollman}
15152708Swollman
15162708Swollman#endif /* defined STD_INSPIRED */
15172708Swollman
15182708Swollman#ifdef CMUCS
15192708Swollman
15202708Swollman/*
15212708Swollman** The following is supplied for compatibility with
15222708Swollman** previous versions of the CMUCS runtime library.
15232708Swollman*/
15242708Swollman
15252708Swollmanlong
15262708Swollmangtime(tmp)
15272708Swollmanstruct tm * const	tmp;
15282708Swollman{
15292708Swollman	const time_t	t = mktime(tmp);
15302708Swollman
15312708Swollman	if (t == WRONG)
15322708Swollman		return -1;
15332708Swollman	return t;
15342708Swollman}
15352708Swollman
15362708Swollman#endif /* defined CMUCS */
15372708Swollman
15382708Swollman/*
15392708Swollman** XXX--is the below the right way to conditionalize??
15402708Swollman*/
15412708Swollman
15422708Swollman#ifdef STD_INSPIRED
15432708Swollman
15442708Swollman/*
15452708Swollman** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
15462708Swollman** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
15472708Swollman** is not the case if we are accounting for leap seconds.
15482708Swollman** So, we provide the following conversion routines for use
15492708Swollman** when exchanging timestamps with POSIX conforming systems.
15502708Swollman*/
15512708Swollman
15522708Swollmanstatic long
15532708Swollmanleapcorr(timep)
15542708Swollmantime_t *	timep;
15552708Swollman{
15562708Swollman	register struct state *		sp;
15572708Swollman	register struct lsinfo *	lp;
15582708Swollman	register int			i;
15592708Swollman
15602708Swollman	sp = lclptr;
15612708Swollman	i = sp->leapcnt;
15622708Swollman	while (--i >= 0) {
15632708Swollman		lp = &sp->lsis[i];
15642708Swollman		if (*timep >= lp->ls_trans)
15652708Swollman			return lp->ls_corr;
15662708Swollman	}
15672708Swollman	return 0;
15682708Swollman}
15692708Swollman
15702708Swollmantime_t
15712708Swollmantime2posix(t)
15722708Swollmantime_t	t;
15732708Swollman{
15749936Swollman	tzset();
15752708Swollman	return t - leapcorr(&t);
15762708Swollman}
15772708Swollman
15782708Swollmantime_t
15792708Swollmanposix2time(t)
15802708Swollmantime_t	t;
15812708Swollman{
15822708Swollman	time_t	x;
15832708Swollman	time_t	y;
15842708Swollman
15859936Swollman	tzset();
15862708Swollman	/*
15872708Swollman	** For a positive leap second hit, the result
15882708Swollman	** is not unique.  For a negative leap second
15892708Swollman	** hit, the corresponding time doesn't exist,
15902708Swollman	** so we return an adjacent second.
15912708Swollman	*/
15922708Swollman	x = t + leapcorr(&t);
15932708Swollman	y = x - leapcorr(&x);
15942708Swollman	if (y < t) {
15952708Swollman		do {
15962708Swollman			x++;
15972708Swollman			y = x - leapcorr(&x);
15982708Swollman		} while (y < t);
15992708Swollman		if (t != y)
16002708Swollman			return x - 1;
16012708Swollman	} else if (y > t) {
16022708Swollman		do {
16032708Swollman			--x;
16042708Swollman			y = x - leapcorr(&x);
16052708Swollman		} while (y > t);
16062708Swollman		if (t != y)
16072708Swollman			return x + 1;
16082708Swollman	}
16092708Swollman	return x;
16102708Swollman}
16112708Swollman
16122708Swollman#endif /* defined STD_INSPIRED */
1613