localtime.c revision 2713
1#ifndef lint
2#ifndef NOID
3static char	elsieid[] = "@(#)localtime.c	7.19";
4#endif /* !defined NOID */
5#endif /* !defined lint */
6
7/*
8** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
9** POSIX-style TZ environment variable handling from Guy Harris
10** (guy@auspex.com).
11*/
12
13/*LINTLIBRARY*/
14
15#include "private.h"
16#include "tzfile.h"
17#include "fcntl.h"
18
19#define ACCESS_MODE	O_RDONLY
20
21#ifdef O_BINARY
22#define OPEN_MODE	(O_RDONLY | O_BINARY)
23#endif /* defined O_BINARY */
24#ifndef O_BINARY
25#define OPEN_MODE	O_RDONLY
26#endif /* !defined O_BINARY */
27
28#ifndef WILDABBR
29/*
30** Someone might make incorrect use of a time zone abbreviation:
31**	1.	They might reference tzname[0] before calling tzset (explicitly
32**	 	or implicitly).
33**	2.	They might reference tzname[1] before calling tzset (explicitly
34**	 	or implicitly).
35**	3.	They might reference tzname[1] after setting to a time zone
36**		in which Daylight Saving Time is never observed.
37**	4.	They might reference tzname[0] after setting to a time zone
38**		in which Standard Time is never observed.
39**	5.	They might reference tm.TM_ZONE after calling offtime.
40** What's best to do in the above cases is open to debate;
41** for now, we just set things up so that in any of the five cases
42** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
43** string "tzname[0] used before set", and similarly for the other cases.
44** And another:  initialize tzname[0] to "ERA", with an explanation in the
45** manual page of what this "time zone abbreviation" means (doing this so
46** that tzname[0] has the "normal" length of three characters).
47*/
48#define WILDABBR	"   "
49#endif /* !defined WILDABBR */
50
51static const char GMT[] = "GMT";
52
53struct ttinfo {				/* time type information */
54	long		tt_gmtoff;	/* GMT offset in seconds */
55	int		tt_isdst;	/* used to set tm_isdst */
56	int		tt_abbrind;	/* abbreviation list index */
57	int		tt_ttisstd;	/* TRUE if transition is std time */
58};
59
60struct lsinfo {				/* leap second information */
61	time_t		ls_trans;	/* transition time */
62	long		ls_corr;	/* correction to apply */
63};
64
65#define BIGGEST(a, b)	(((a) > (b)) ? (a) : (b))
66
67#ifdef TZNAME_MAX
68#define MY_TZNAME_MAX	TZNAME_MAX
69#endif /* defined TZNAME_MAX */
70#ifndef TZNAME_MAX
71#define MY_TZNAME_MAX	255
72#endif /* !defined TZNAME_MAX */
73
74struct state {
75	int		leapcnt;
76	int		timecnt;
77	int		typecnt;
78	int		charcnt;
79	time_t		ats[TZ_MAX_TIMES];
80	unsigned char	types[TZ_MAX_TIMES];
81	struct ttinfo	ttis[TZ_MAX_TYPES];
82	char		chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof GMT),
83				(2 * (MY_TZNAME_MAX + 1)))];
84	struct lsinfo	lsis[TZ_MAX_LEAPS];
85};
86
87struct rule {
88	int		r_type;		/* type of rule--see below */
89	int		r_day;		/* day number of rule */
90	int		r_week;		/* week number of rule */
91	int		r_mon;		/* month number of rule */
92	long		r_time;		/* transition time of rule */
93};
94
95#define JULIAN_DAY		0	/* Jn - Julian day */
96#define DAY_OF_YEAR		1	/* n - day of year */
97#define MONTH_NTH_DAY_OF_WEEK	2	/* Mm.n.d - month, week, day of week */
98
99/*
100** Prototypes for static functions.
101*/
102
103static long		detzcode P((const char * codep));
104static const char *	getzname P((const char * strp));
105static const char *	getnum P((const char * strp, int * nump, int min,
106				int max));
107static const char *	getsecs P((const char * strp, long * secsp));
108static const char *	getoffset P((const char * strp, long * offsetp));
109static const char *	getrule P((const char * strp, struct rule * rulep));
110static void		gmtload P((struct state * sp));
111static void		gmtsub P((const time_t * timep, long offset,
112				struct tm * tmp));
113static void		localsub P((const time_t * timep, long offset,
114				struct tm * tmp));
115static int		increment_overflow P((int * number, int delta));
116static int		normalize_overflow P((int * tensptr, int * unitsptr,
117				int base));
118static void		settzname P((void));
119static time_t		time1 P((struct tm * tmp, void (* funcp)(),
120				long offset));
121static time_t		time2 P((struct tm *tmp, void (* funcp)(),
122				long offset, int * okayp));
123static void		timesub P((const time_t * timep, long offset,
124				const struct state * sp, struct tm * tmp));
125static int		tmcomp P((const struct tm * atmp,
126				const struct tm * btmp));
127static time_t		transtime P((time_t janfirst, int year,
128				const struct rule * rulep, long offset));
129static int		tzload P((const char * name, struct state * sp));
130static int		tzparse P((const char * name, struct state * sp,
131				int lastditch));
132
133#ifdef ALL_STATE
134static struct state *	lclptr;
135static struct state *	gmtptr;
136#endif /* defined ALL_STATE */
137
138#ifndef ALL_STATE
139static struct state	lclmem;
140static struct state	gmtmem;
141#define lclptr		(&lclmem)
142#define gmtptr		(&gmtmem)
143#endif /* State Farm */
144
145static int		lcl_is_set;
146static int		gmt_is_set;
147
148char *			tzname[2] = {
149	WILDABBR,
150	WILDABBR
151};
152
153#ifdef USG_COMPAT
154time_t			timezone = 0;
155int			daylight = 0;
156#endif /* defined USG_COMPAT */
157
158#ifdef ALTZONE
159time_t			altzone = 0;
160#endif /* defined ALTZONE */
161
162static long
163detzcode(codep)
164const char * const	codep;
165{
166	register long	result;
167	register int	i;
168
169	result = 0;
170	for (i = 0; i < 4; ++i)
171		result = (result << 8) | (codep[i] & 0xff);
172	return result;
173}
174
175static void
176settzname()
177{
178	register const struct state * const	sp = lclptr;
179	register int				i;
180
181	tzname[0] = WILDABBR;
182	tzname[1] = WILDABBR;
183#ifdef USG_COMPAT
184	daylight = 0;
185	timezone = 0;
186#endif /* defined USG_COMPAT */
187#ifdef ALTZONE
188	altzone = 0;
189#endif /* defined ALTZONE */
190#ifdef ALL_STATE
191	if (sp == NULL) {
192		tzname[0] = tzname[1] = GMT;
193		return;
194	}
195#endif /* defined ALL_STATE */
196	for (i = 0; i < sp->typecnt; ++i) {
197		register const struct ttinfo * const	ttisp = &sp->ttis[i];
198
199		tzname[ttisp->tt_isdst] =
200			(char *) &sp->chars[ttisp->tt_abbrind];
201#ifdef USG_COMPAT
202		if (ttisp->tt_isdst)
203			daylight = 1;
204		if (i == 0 || !ttisp->tt_isdst)
205			timezone = -(ttisp->tt_gmtoff);
206#endif /* defined USG_COMPAT */
207#ifdef ALTZONE
208		if (i == 0 || ttisp->tt_isdst)
209			altzone = -(ttisp->tt_gmtoff);
210#endif /* defined ALTZONE */
211	}
212	/*
213	** And to get the latest zone names into tzname. . .
214	*/
215	for (i = 0; i < sp->timecnt; ++i) {
216		register const struct ttinfo * const	ttisp =
217							&sp->ttis[
218								sp->types[i]];
219
220		tzname[ttisp->tt_isdst] =
221			(char *) &sp->chars[ttisp->tt_abbrind];
222	}
223}
224
225static int
226tzload(name, sp)
227register const char *		name;
228register struct state * const	sp;
229{
230	register const char *	p;
231	register int		i;
232	register int		fid;
233
234	if (name == NULL && (name = TZDEFAULT) == NULL)
235		return -1;
236	{
237		register int 	doaccess;
238		char		fullname[FILENAME_MAX + 1];
239
240		if (name[0] == ':')
241			++name;
242		doaccess = name[0] == '/';
243		if (!doaccess) {
244			if ((p = TZDIR) == NULL)
245				return -1;
246			if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
247				return -1;
248			(void) strcpy(fullname, p);
249			(void) strcat(fullname, "/");
250			(void) strcat(fullname, name);
251			/*
252			** Set doaccess if '.' (as in "../") shows up in name.
253			*/
254			if (strchr(name, '.') != NULL)
255				doaccess = TRUE;
256			name = fullname;
257		}
258		if (doaccess && access(name, ACCESS_MODE) != 0)
259			return -1;
260		if ((fid = open(name, OPEN_MODE)) == -1)
261			return -1;
262	}
263	{
264		register const struct tzhead *	tzhp;
265		char				buf[sizeof *sp + sizeof *tzhp];
266		int				ttisstdcnt;
267
268		i = read(fid, buf, sizeof buf);
269		if (close(fid) != 0 || i < sizeof *tzhp)
270			return -1;
271		tzhp = (struct tzhead *) buf;
272		ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
273		sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
274		sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
275		sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
276		sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
277		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
278			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
279			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
280			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
281			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
282				return -1;
283		if (i < sizeof *tzhp +
284			sp->timecnt * (4 + sizeof (char)) +
285			sp->typecnt * (4 + 2 * sizeof (char)) +
286			sp->charcnt * sizeof (char) +
287			sp->leapcnt * 2 * 4 +
288			ttisstdcnt * sizeof (char))
289				return -1;
290		p = buf + sizeof *tzhp;
291		for (i = 0; i < sp->timecnt; ++i) {
292			sp->ats[i] = detzcode(p);
293			p += 4;
294		}
295		for (i = 0; i < sp->timecnt; ++i) {
296			sp->types[i] = (unsigned char) *p++;
297			if (sp->types[i] >= sp->typecnt)
298				return -1;
299		}
300		for (i = 0; i < sp->typecnt; ++i) {
301			register struct ttinfo *	ttisp;
302
303			ttisp = &sp->ttis[i];
304			ttisp->tt_gmtoff = detzcode(p);
305			p += 4;
306			ttisp->tt_isdst = (unsigned char) *p++;
307			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
308				return -1;
309			ttisp->tt_abbrind = (unsigned char) *p++;
310			if (ttisp->tt_abbrind < 0 ||
311				ttisp->tt_abbrind > sp->charcnt)
312					return -1;
313		}
314		for (i = 0; i < sp->charcnt; ++i)
315			sp->chars[i] = *p++;
316		sp->chars[i] = '\0';	/* ensure '\0' at end */
317		for (i = 0; i < sp->leapcnt; ++i) {
318			register struct lsinfo *	lsisp;
319
320			lsisp = &sp->lsis[i];
321			lsisp->ls_trans = detzcode(p);
322			p += 4;
323			lsisp->ls_corr = detzcode(p);
324			p += 4;
325		}
326		for (i = 0; i < sp->typecnt; ++i) {
327			register struct ttinfo *	ttisp;
328
329			ttisp = &sp->ttis[i];
330			if (ttisstdcnt == 0)
331				ttisp->tt_ttisstd = FALSE;
332			else {
333				ttisp->tt_ttisstd = *p++;
334				if (ttisp->tt_ttisstd != TRUE &&
335					ttisp->tt_ttisstd != FALSE)
336						return -1;
337			}
338		}
339	}
340	return 0;
341}
342
343static const int	mon_lengths[2][MONSPERYEAR] = {
344	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
345	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
346};
347
348static const int	year_lengths[2] = {
349	DAYSPERNYEAR, DAYSPERLYEAR
350};
351
352/*
353** Given a pointer into a time zone string, scan until a character that is not
354** a valid character in a zone name is found.  Return a pointer to that
355** character.
356*/
357
358static const char *
359getzname(strp)
360register const char *	strp;
361{
362	register char	c;
363
364	while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
365		c != '+')
366			++strp;
367	return strp;
368}
369
370/*
371** Given a pointer into a time zone string, extract a number from that string.
372** Check that the number is within a specified range; if it is not, return
373** NULL.
374** Otherwise, return a pointer to the first character not part of the number.
375*/
376
377static const char *
378getnum(strp, nump, min, max)
379register const char *	strp;
380int * const		nump;
381const int		min;
382const int		max;
383{
384	register char	c;
385	register int	num;
386
387	if (strp == NULL || !isdigit(*strp))
388		return NULL;
389	num = 0;
390	while ((c = *strp) != '\0' && isdigit(c)) {
391		num = num * 10 + (c - '0');
392		if (num > max)
393			return NULL;	/* illegal value */
394		++strp;
395	}
396	if (num < min)
397		return NULL;		/* illegal value */
398	*nump = num;
399	return strp;
400}
401
402/*
403** Given a pointer into a time zone string, extract a number of seconds,
404** in hh[:mm[:ss]] form, from the string.
405** If any error occurs, return NULL.
406** Otherwise, return a pointer to the first character not part of the number
407** of seconds.
408*/
409
410static const char *
411getsecs(strp, secsp)
412register const char *	strp;
413long * const		secsp;
414{
415	int	num;
416
417	strp = getnum(strp, &num, 0, HOURSPERDAY);
418	if (strp == NULL)
419		return NULL;
420	*secsp = num * SECSPERHOUR;
421	if (*strp == ':') {
422		++strp;
423		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
424		if (strp == NULL)
425			return NULL;
426		*secsp += num * SECSPERMIN;
427		if (*strp == ':') {
428			++strp;
429			strp = getnum(strp, &num, 0, SECSPERMIN - 1);
430			if (strp == NULL)
431				return NULL;
432			*secsp += num;
433		}
434	}
435	return strp;
436}
437
438/*
439** Given a pointer into a time zone string, extract an offset, in
440** [+-]hh[:mm[:ss]] form, from the string.
441** If any error occurs, return NULL.
442** Otherwise, return a pointer to the first character not part of the time.
443*/
444
445static const char *
446getoffset(strp, offsetp)
447register const char *	strp;
448long * const		offsetp;
449{
450	register int	neg;
451
452	if (*strp == '-') {
453		neg = 1;
454		++strp;
455	} else if (isdigit(*strp) || *strp++ == '+')
456		neg = 0;
457	else	return NULL;		/* illegal offset */
458	strp = getsecs(strp, offsetp);
459	if (strp == NULL)
460		return NULL;		/* illegal time */
461	if (neg)
462		*offsetp = -*offsetp;
463	return strp;
464}
465
466/*
467** Given a pointer into a time zone string, extract a rule in the form
468** date[/time].  See POSIX section 8 for the format of "date" and "time".
469** If a valid rule is not found, return NULL.
470** Otherwise, return a pointer to the first character not part of the rule.
471*/
472
473static const char *
474getrule(strp, rulep)
475const char *			strp;
476register struct rule * const	rulep;
477{
478	if (*strp == 'J') {
479		/*
480		** Julian day.
481		*/
482		rulep->r_type = JULIAN_DAY;
483		++strp;
484		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
485	} else if (*strp == 'M') {
486		/*
487		** Month, week, day.
488		*/
489		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
490		++strp;
491		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
492		if (strp == NULL)
493			return NULL;
494		if (*strp++ != '.')
495			return NULL;
496		strp = getnum(strp, &rulep->r_week, 1, 5);
497		if (strp == NULL)
498			return NULL;
499		if (*strp++ != '.')
500			return NULL;
501		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
502	} else if (isdigit(*strp)) {
503		/*
504		** Day of year.
505		*/
506		rulep->r_type = DAY_OF_YEAR;
507		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
508	} else	return NULL;		/* invalid format */
509	if (strp == NULL)
510		return NULL;
511	if (*strp == '/') {
512		/*
513		** Time specified.
514		*/
515		++strp;
516		strp = getsecs(strp, &rulep->r_time);
517	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
518	return strp;
519}
520
521/*
522** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
523** year, a rule, and the offset from GMT at the time that rule takes effect,
524** calculate the Epoch-relative time that rule takes effect.
525*/
526
527static time_t
528transtime(janfirst, year, rulep, offset)
529const time_t				janfirst;
530const int				year;
531register const struct rule * const	rulep;
532const long				offset;
533{
534	register int	leapyear;
535	register time_t	value;
536	register int	i;
537	int		d, m1, yy0, yy1, yy2, dow;
538
539	leapyear = isleap(year);
540	switch (rulep->r_type) {
541
542	case JULIAN_DAY:
543		/*
544		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
545		** years.
546		** In non-leap years, or if the day number is 59 or less, just
547		** add SECSPERDAY times the day number-1 to the time of
548		** January 1, midnight, to get the day.
549		*/
550		value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
551		if (leapyear && rulep->r_day >= 60)
552			value += SECSPERDAY;
553		break;
554
555	case DAY_OF_YEAR:
556		/*
557		** n - day of year.
558		** Just add SECSPERDAY times the day number to the time of
559		** January 1, midnight, to get the day.
560		*/
561		value = janfirst + rulep->r_day * SECSPERDAY;
562		break;
563
564	case MONTH_NTH_DAY_OF_WEEK:
565		/*
566		** Mm.n.d - nth "dth day" of month m.
567		*/
568		value = janfirst;
569		for (i = 0; i < rulep->r_mon - 1; ++i)
570			value += mon_lengths[leapyear][i] * SECSPERDAY;
571
572		/*
573		** Use Zeller's Congruence to get day-of-week of first day of
574		** month.
575		*/
576		m1 = (rulep->r_mon + 9) % 12 + 1;
577		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
578		yy1 = yy0 / 100;
579		yy2 = yy0 % 100;
580		dow = ((26 * m1 - 2) / 10 +
581			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
582		if (dow < 0)
583			dow += DAYSPERWEEK;
584
585		/*
586		** "dow" is the day-of-week of the first day of the month.  Get
587		** the day-of-month (zero-origin) of the first "dow" day of the
588		** month.
589		*/
590		d = rulep->r_day - dow;
591		if (d < 0)
592			d += DAYSPERWEEK;
593		for (i = 1; i < rulep->r_week; ++i) {
594			if (d + DAYSPERWEEK >=
595				mon_lengths[leapyear][rulep->r_mon - 1])
596					break;
597			d += DAYSPERWEEK;
598		}
599
600		/*
601		** "d" is the day-of-month (zero-origin) of the day we want.
602		*/
603		value += d * SECSPERDAY;
604		break;
605	}
606
607	/*
608	** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
609	** question.  To get the Epoch-relative time of the specified local
610	** time on that day, add the transition time and the current offset
611	** from GMT.
612	*/
613	return value + rulep->r_time + offset;
614}
615
616/*
617** Given a POSIX section 8-style TZ string, fill in the rule tables as
618** appropriate.
619*/
620
621static int
622tzparse(name, sp, lastditch)
623const char *			name;
624register struct state * const	sp;
625const int			lastditch;
626{
627	const char *			stdname;
628	const char *			dstname;
629	int				stdlen;
630	int				dstlen;
631	long				stdoffset;
632	long				dstoffset;
633	register time_t *		atp;
634	register unsigned char *	typep;
635	register char *			cp;
636	register int			load_result;
637
638	stdname = name;
639	if (lastditch) {
640		stdlen = strlen(name);	/* length of standard zone name */
641		name += stdlen;
642		if (stdlen >= sizeof sp->chars)
643			stdlen = (sizeof sp->chars) - 1;
644	} else {
645		name = getzname(name);
646		stdlen = name - stdname;
647		if (stdlen < 3)
648			return -1;
649	}
650	if (*name == '\0')
651		return -1;	/* was "stdoffset = 0;" */
652	else {
653		name = getoffset(name, &stdoffset);
654		if (name == NULL)
655			return -1;
656	}
657	load_result = tzload(TZDEFRULES, sp);
658	if (load_result != 0)
659		sp->leapcnt = 0;		/* so, we're off a little */
660	if (*name != '\0') {
661		dstname = name;
662		name = getzname(name);
663		dstlen = name - dstname;	/* length of DST zone name */
664		if (dstlen < 3)
665			return -1;
666		if (*name != '\0' && *name != ',' && *name != ';') {
667			name = getoffset(name, &dstoffset);
668			if (name == NULL)
669				return -1;
670		} else	dstoffset = stdoffset - SECSPERHOUR;
671		if (*name == ',' || *name == ';') {
672			struct rule	start;
673			struct rule	end;
674			register int	year;
675			register time_t	janfirst;
676			time_t		starttime;
677			time_t		endtime;
678
679			++name;
680			if ((name = getrule(name, &start)) == NULL)
681				return -1;
682			if (*name++ != ',')
683				return -1;
684			if ((name = getrule(name, &end)) == NULL)
685				return -1;
686			if (*name != '\0')
687				return -1;
688			sp->typecnt = 2;	/* standard time and DST */
689			/*
690			** Two transitions per year, from EPOCH_YEAR to 2037.
691			*/
692			sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
693			if (sp->timecnt > TZ_MAX_TIMES)
694				return -1;
695			sp->ttis[0].tt_gmtoff = -dstoffset;
696			sp->ttis[0].tt_isdst = 1;
697			sp->ttis[0].tt_abbrind = stdlen + 1;
698			sp->ttis[1].tt_gmtoff = -stdoffset;
699			sp->ttis[1].tt_isdst = 0;
700			sp->ttis[1].tt_abbrind = 0;
701			atp = sp->ats;
702			typep = sp->types;
703			janfirst = 0;
704			for (year = EPOCH_YEAR; year <= 2037; ++year) {
705				starttime = transtime(janfirst, year, &start,
706					stdoffset);
707				endtime = transtime(janfirst, year, &end,
708					dstoffset);
709				if (starttime > endtime) {
710					*atp++ = endtime;
711					*typep++ = 1;	/* DST ends */
712					*atp++ = starttime;
713					*typep++ = 0;	/* DST begins */
714				} else {
715					*atp++ = starttime;
716					*typep++ = 0;	/* DST begins */
717					*atp++ = endtime;
718					*typep++ = 1;	/* DST ends */
719				}
720				janfirst += year_lengths[isleap(year)] *
721					SECSPERDAY;
722			}
723		} else {
724			int		sawstd;
725			int		sawdst;
726			long		stdfix;
727			long		dstfix;
728			long		oldfix;
729			int		isdst;
730			register int	i;
731
732			if (*name != '\0')
733				return -1;
734			if (load_result != 0)
735				return -1;
736			/*
737			** Compute the difference between the real and
738			** prototype standard and summer time offsets
739			** from GMT, and put the real standard and summer
740			** time offsets into the rules in place of the
741			** prototype offsets.
742			*/
743			sawstd = FALSE;
744			sawdst = FALSE;
745			stdfix = 0;
746			dstfix = 0;
747			for (i = 0; i < sp->typecnt; ++i) {
748				if (sp->ttis[i].tt_isdst) {
749					oldfix = dstfix;
750					dstfix = sp->ttis[i].tt_gmtoff +
751						dstoffset;
752					if (sawdst && (oldfix != dstfix))
753						return -1;
754					sp->ttis[i].tt_gmtoff = -dstoffset;
755					sp->ttis[i].tt_abbrind = stdlen + 1;
756					sawdst = TRUE;
757				} else {
758					oldfix = stdfix;
759					stdfix = sp->ttis[i].tt_gmtoff +
760						stdoffset;
761					if (sawstd && (oldfix != stdfix))
762						return -1;
763					sp->ttis[i].tt_gmtoff = -stdoffset;
764					sp->ttis[i].tt_abbrind = 0;
765					sawstd = TRUE;
766				}
767			}
768			/*
769			** Make sure we have both standard and summer time.
770			*/
771			if (!sawdst || !sawstd)
772				return -1;
773			/*
774			** Now correct the transition times by shifting
775			** them by the difference between the real and
776			** prototype offsets.  Note that this difference
777			** can be different in standard and summer time;
778			** the prototype probably has a 1-hour difference
779			** between standard and summer time, but a different
780			** difference can be specified in TZ.
781			*/
782			isdst = FALSE;	/* we start in standard time */
783			for (i = 0; i < sp->timecnt; ++i) {
784				register const struct ttinfo *	ttisp;
785
786				/*
787				** If summer time is in effect, and the
788				** transition time was not specified as
789				** standard time, add the summer time
790				** offset to the transition time;
791				** otherwise, add the standard time offset
792				** to the transition time.
793				*/
794				ttisp = &sp->ttis[sp->types[i]];
795				sp->ats[i] +=
796					(isdst && !ttisp->tt_ttisstd) ?
797						dstfix : stdfix;
798				isdst = ttisp->tt_isdst;
799			}
800		}
801	} else {
802		dstlen = 0;
803		sp->typecnt = 1;		/* only standard time */
804		sp->timecnt = 0;
805		sp->ttis[0].tt_gmtoff = -stdoffset;
806		sp->ttis[0].tt_isdst = 0;
807		sp->ttis[0].tt_abbrind = 0;
808	}
809	sp->charcnt = stdlen + 1;
810	if (dstlen != 0)
811		sp->charcnt += dstlen + 1;
812	if (sp->charcnt > sizeof sp->chars)
813		return -1;
814	cp = sp->chars;
815	(void) strncpy(cp, stdname, stdlen);
816	cp += stdlen;
817	*cp++ = '\0';
818	if (dstlen != 0) {
819		(void) strncpy(cp, dstname, dstlen);
820		*(cp + dstlen) = '\0';
821	}
822	return 0;
823}
824
825static void
826gmtload(sp)
827struct state * const	sp;
828{
829	if (tzload(GMT, sp) != 0)
830		(void) tzparse(GMT, sp, TRUE);
831}
832
833#ifndef STD_INSPIRED
834static
835#endif /* !defined STD_INSPIRED */
836void
837tzsetwall()
838{
839	lcl_is_set = TRUE;
840#ifdef ALL_STATE
841	if (lclptr == NULL) {
842		lclptr = (struct state *) malloc(sizeof *lclptr);
843		if (lclptr == NULL) {
844			settzname();	/* all we can do */
845			return;
846		}
847	}
848#endif /* defined ALL_STATE */
849	if (tzload((char *) NULL, lclptr) != 0)
850		gmtload(lclptr);
851	settzname();
852}
853
854void
855tzset()
856{
857	register const char *	name;
858
859	name = getenv("TZ");
860	if (name == NULL) {
861		tzsetwall();
862		return;
863	}
864	lcl_is_set = TRUE;
865#ifdef ALL_STATE
866	if (lclptr == NULL) {
867		lclptr = (struct state *) malloc(sizeof *lclptr);
868		if (lclptr == NULL) {
869			settzname();	/* all we can do */
870			return;
871		}
872	}
873#endif /* defined ALL_STATE */
874	if (*name == '\0') {
875		/*
876		** User wants it fast rather than right.
877		*/
878		lclptr->leapcnt = 0;		/* so, we're off a little */
879		lclptr->timecnt = 0;
880		lclptr->ttis[0].tt_gmtoff = 0;
881		lclptr->ttis[0].tt_abbrind = 0;
882		(void) strcpy(lclptr->chars, GMT);
883	} else if (tzload(name, lclptr) != 0)
884		if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
885			(void) gmtload(lclptr);
886	settzname();
887}
888
889/*
890** The easy way to behave "as if no library function calls" localtime
891** is to not call it--so we drop its guts into "localsub", which can be
892** freely called.  (And no, the PANS doesn't require the above behavior--
893** but it *is* desirable.)
894**
895** The unused offset argument is for the benefit of mktime variants.
896*/
897
898/*ARGSUSED*/
899static void
900localsub(timep, offset, tmp)
901const time_t * const	timep;
902const long		offset;
903struct tm * const	tmp;
904{
905	register const struct state *	sp;
906	register const struct ttinfo *	ttisp;
907	register int			i;
908	const time_t			t = *timep;
909
910	if (!lcl_is_set)
911		tzset();
912	sp = lclptr;
913#ifdef ALL_STATE
914	if (sp == NULL) {
915		gmtsub(timep, offset, tmp);
916		return;
917	}
918#endif /* defined ALL_STATE */
919	if (sp->timecnt == 0 || t < sp->ats[0]) {
920		i = 0;
921		while (sp->ttis[i].tt_isdst)
922			if (++i >= sp->typecnt) {
923				i = 0;
924				break;
925			}
926	} else {
927		for (i = 1; i < sp->timecnt; ++i)
928			if (t < sp->ats[i])
929				break;
930		i = sp->types[i - 1];
931	}
932	ttisp = &sp->ttis[i];
933	/*
934	** To get (wrong) behavior that's compatible with System V Release 2.0
935	** you'd replace the statement below with
936	**	t += ttisp->tt_gmtoff;
937	**	timesub(&t, 0L, sp, tmp);
938	*/
939	timesub(&t, ttisp->tt_gmtoff, sp, tmp);
940	tmp->tm_isdst = ttisp->tt_isdst;
941	tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
942#ifdef TM_ZONE
943	tmp->TM_ZONE = (char *)&sp->chars[ttisp->tt_abbrind];
944#endif /* defined TM_ZONE */
945}
946
947struct tm *
948localtime(timep)
949const time_t * const	timep;
950{
951	static struct tm	tm;
952
953	localsub(timep, 0L, &tm);
954	return &tm;
955}
956
957/*
958** gmtsub is to gmtime as localsub is to localtime.
959*/
960
961static void
962gmtsub(timep, offset, tmp)
963const time_t * const	timep;
964const long		offset;
965struct tm * const	tmp;
966{
967	if (!gmt_is_set) {
968		gmt_is_set = TRUE;
969#ifdef ALL_STATE
970		gmtptr = (struct state *) malloc(sizeof *gmtptr);
971		if (gmtptr != NULL)
972#endif /* defined ALL_STATE */
973			gmtload(gmtptr);
974	}
975	timesub(timep, offset, gmtptr, tmp);
976#ifdef TM_ZONE
977	/*
978	** Could get fancy here and deliver something such as
979	** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
980	** but this is no time for a treasure hunt.
981	*/
982	if (offset != 0)
983		tmp->TM_ZONE = WILDABBR;
984	else {
985#ifdef ALL_STATE
986		if (gmtptr == NULL)
987			tmp->TM_ZONE = GMT;
988		else	tmp->TM_ZONE = gmtptr->chars;
989#endif /* defined ALL_STATE */
990#ifndef ALL_STATE
991		tmp->TM_ZONE = gmtptr->chars;
992#endif /* State Farm */
993	}
994#endif /* defined TM_ZONE */
995}
996
997struct tm *
998gmtime(timep)
999const time_t * const	timep;
1000{
1001	static struct tm	tm;
1002
1003	gmtsub(timep, 0L, &tm);
1004	return &tm;
1005}
1006
1007#ifdef STD_INSPIRED
1008
1009struct tm *
1010offtime(timep, offset)
1011const time_t * const	timep;
1012const long		offset;
1013{
1014	static struct tm	tm;
1015
1016	gmtsub(timep, offset, &tm);
1017	return &tm;
1018}
1019
1020#endif /* defined STD_INSPIRED */
1021
1022static void
1023timesub(timep, offset, sp, tmp)
1024const time_t * const			timep;
1025const long				offset;
1026register const struct state * const	sp;
1027register struct tm * const		tmp;
1028{
1029	register const struct lsinfo *	lp;
1030	register long			days;
1031	register long			rem;
1032	register int			y;
1033	register int			yleap;
1034	register const int *		ip;
1035	register long			corr;
1036	register int			hit;
1037	register int			i;
1038
1039	corr = 0;
1040	hit = 0;
1041#ifdef ALL_STATE
1042	i = (sp == NULL) ? 0 : sp->leapcnt;
1043#endif /* defined ALL_STATE */
1044#ifndef ALL_STATE
1045	i = sp->leapcnt;
1046#endif /* State Farm */
1047	while (--i >= 0) {
1048		lp = &sp->lsis[i];
1049		if (*timep >= lp->ls_trans) {
1050			if (*timep == lp->ls_trans) {
1051				hit = ((i == 0 && lp->ls_corr > 0) ||
1052					lp->ls_corr > sp->lsis[i - 1].ls_corr);
1053				if (hit)
1054					while (i > 0 &&
1055						sp->lsis[i].ls_trans ==
1056						sp->lsis[i - 1].ls_trans + 1 &&
1057						sp->lsis[i].ls_corr ==
1058						sp->lsis[i - 1].ls_corr + 1) {
1059							++hit;
1060							--i;
1061					}
1062			}
1063			corr = lp->ls_corr;
1064			break;
1065		}
1066	}
1067	days = *timep / SECSPERDAY;
1068	rem = *timep % SECSPERDAY;
1069#ifdef mc68k
1070	if (*timep == 0x80000000) {
1071		/*
1072		** A 3B1 muffs the division on the most negative number.
1073		*/
1074		days = -24855;
1075		rem = -11648;
1076	}
1077#endif /* mc68k */
1078	rem += (offset - corr);
1079	while (rem < 0) {
1080		rem += SECSPERDAY;
1081		--days;
1082	}
1083	while (rem >= SECSPERDAY) {
1084		rem -= SECSPERDAY;
1085		++days;
1086	}
1087	tmp->tm_hour = (int) (rem / SECSPERHOUR);
1088	rem = rem % SECSPERHOUR;
1089	tmp->tm_min = (int) (rem / SECSPERMIN);
1090	tmp->tm_sec = (int) (rem % SECSPERMIN);
1091	if (hit)
1092		/*
1093		** A positive leap second requires a special
1094		** representation.  This uses "... ??:59:60" et seq.
1095		*/
1096		tmp->tm_sec += hit;
1097	tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
1098	if (tmp->tm_wday < 0)
1099		tmp->tm_wday += DAYSPERWEEK;
1100	y = EPOCH_YEAR;
1101	if (days >= 0)
1102		for ( ; ; ) {
1103			yleap = isleap(y);
1104			if (days < (long) year_lengths[yleap])
1105				break;
1106			++y;
1107			days = days - (long) year_lengths[yleap];
1108		}
1109	else do {
1110		--y;
1111		yleap = isleap(y);
1112		days = days + (long) year_lengths[yleap];
1113	} while (days < 0);
1114	tmp->tm_year = y - TM_YEAR_BASE;
1115	tmp->tm_yday = (int) days;
1116	ip = mon_lengths[yleap];
1117	for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
1118		days = days - (long) ip[tmp->tm_mon];
1119	tmp->tm_mday = (int) (days + 1);
1120	tmp->tm_isdst = 0;
1121#ifdef TM_GMTOFF
1122	tmp->TM_GMTOFF = offset;
1123#endif /* defined TM_GMTOFF */
1124}
1125
1126char *
1127ctime(timep)
1128const time_t * const	timep;
1129{
1130	return asctime(localtime(timep));
1131}
1132
1133/*
1134** Adapted from code provided by Robert Elz, who writes:
1135**	The "best" way to do mktime I think is based on an idea of Bob
1136**	Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1137**	It does a binary search of the time_t space.  Since time_t's are
1138**	just 32 bits, its a max of 32 iterations (even at 64 bits it
1139**	would still be very reasonable).
1140*/
1141
1142#ifndef WRONG
1143#define WRONG	(-1)
1144#endif /* !defined WRONG */
1145
1146/*
1147** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
1148*/
1149
1150static int
1151increment_overflow(number, delta)
1152int *	number;
1153int	delta;
1154{
1155	int number0;
1156
1157	number0 = *number;
1158	*number += delta;
1159	return (*number < number0) != (delta < 0);
1160}
1161
1162static int
1163normalize_overflow(tensptr, unitsptr, base)
1164int * const	tensptr;
1165int * const	unitsptr;
1166const int	base;
1167{
1168	register int	tensdelta;
1169
1170	tensdelta = (*unitsptr >= 0) ?
1171		(*unitsptr / base) :
1172		(-1 - (-1 - *unitsptr) / base);
1173	*unitsptr -= tensdelta * base;
1174	return increment_overflow(tensptr, tensdelta);
1175}
1176
1177static int
1178tmcomp(atmp, btmp)
1179register const struct tm * const atmp;
1180register const struct tm * const btmp;
1181{
1182	register int	result;
1183
1184	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1185		(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1186		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1187		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1188		(result = (atmp->tm_min - btmp->tm_min)) == 0)
1189			result = atmp->tm_sec - btmp->tm_sec;
1190	return result;
1191}
1192
1193static time_t
1194time2(tmp, funcp, offset, okayp)
1195struct tm * const	tmp;
1196void (* const		funcp)();
1197const long		offset;
1198int * const		okayp;
1199{
1200	register const struct state *	sp;
1201	register int			dir;
1202	register int			bits;
1203	register int			i, j ;
1204	register int			saved_seconds;
1205	time_t				newt;
1206	time_t				t;
1207	struct tm			yourtm, mytm;
1208
1209	*okayp = FALSE;
1210	yourtm = *tmp;
1211	if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1212		return WRONG;
1213	if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1214		return WRONG;
1215	if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
1216		return WRONG;
1217	/*
1218	** Turn yourtm.tm_year into an actual year number for now.
1219	** It is converted back to an offset from TM_YEAR_BASE later.
1220	*/
1221	if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
1222		return WRONG;
1223	while (yourtm.tm_mday <= 0) {
1224		if (increment_overflow(&yourtm.tm_year, -1))
1225			return WRONG;
1226		yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)];
1227	}
1228	while (yourtm.tm_mday > DAYSPERLYEAR) {
1229		yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)];
1230		if (increment_overflow(&yourtm.tm_year, 1))
1231			return WRONG;
1232	}
1233	for ( ; ; ) {
1234		i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
1235		if (yourtm.tm_mday <= i)
1236			break;
1237		yourtm.tm_mday -= i;
1238		if (++yourtm.tm_mon >= MONSPERYEAR) {
1239			yourtm.tm_mon = 0;
1240			if (increment_overflow(&yourtm.tm_year, 1))
1241				return WRONG;
1242		}
1243	}
1244	if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
1245		return WRONG;
1246	if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
1247		/*
1248		** We can't set tm_sec to 0, because that might push the
1249		** time below the minimum representable time.
1250		** Set tm_sec to 59 instead.
1251		** This assumes that the minimum representable time is
1252		** not in the same minute that a leap second was deleted from,
1253		** which is a safer assumption than using 58 would be.
1254		*/
1255		if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1256			return WRONG;
1257		saved_seconds = yourtm.tm_sec;
1258		yourtm.tm_sec = SECSPERMIN - 1;
1259	} else {
1260		saved_seconds = yourtm.tm_sec;
1261		yourtm.tm_sec = 0;
1262	}
1263	/*
1264	** Calculate the number of magnitude bits in a time_t
1265	** (this works regardless of whether time_t is
1266	** signed or unsigned, though lint complains if unsigned).
1267	*/
1268	for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
1269		continue;
1270	/*
1271	** If time_t is signed, then 0 is the median value,
1272	** if time_t is unsigned, then 1 << bits is median.
1273	*/
1274	t = (t < 0) ? 0 : ((time_t) 1 << bits);
1275	for ( ; ; ) {
1276		(*funcp)(&t, offset, &mytm);
1277		dir = tmcomp(&mytm, &yourtm);
1278		if (dir != 0) {
1279			if (bits-- < 0)
1280				return WRONG;
1281			if (bits < 0)
1282				--t;
1283			else if (dir > 0)
1284				t -= (time_t) 1 << bits;
1285			else	t += (time_t) 1 << bits;
1286			continue;
1287		}
1288		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1289			break;
1290		/*
1291		** Right time, wrong type.
1292		** Hunt for right time, right type.
1293		** It's okay to guess wrong since the guess
1294		** gets checked.
1295		*/
1296		/*
1297		** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1298		*/
1299		sp = (const struct state *)
1300			(((void *) funcp == (void *) localsub) ?
1301			lclptr : gmtptr);
1302#ifdef ALL_STATE
1303		if (sp == NULL)
1304			return WRONG;
1305#endif /* defined ALL_STATE */
1306		for (i = 0; i < sp->typecnt; ++i) {
1307			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1308				continue;
1309			for (j = 0; j < sp->typecnt; ++j) {
1310				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1311					continue;
1312				newt = t + sp->ttis[j].tt_gmtoff -
1313					sp->ttis[i].tt_gmtoff;
1314				(*funcp)(&newt, offset, &mytm);
1315				if (tmcomp(&mytm, &yourtm) != 0)
1316					continue;
1317				if (mytm.tm_isdst != yourtm.tm_isdst)
1318					continue;
1319				/*
1320				** We have a match.
1321				*/
1322				t = newt;
1323				goto label;
1324			}
1325		}
1326		return WRONG;
1327	}
1328label:
1329	newt = t + saved_seconds;
1330	if ((newt < t) != (saved_seconds < 0))
1331		return WRONG;
1332	t = newt;
1333	(*funcp)(&t, offset, tmp);
1334	*okayp = TRUE;
1335	return t;
1336}
1337
1338static time_t
1339time1(tmp, funcp, offset)
1340struct tm * const	tmp;
1341void (* const		funcp)();
1342const long		offset;
1343{
1344	register time_t			t;
1345	register const struct state *	sp;
1346	register int			samei, otheri;
1347	int				okay;
1348
1349	if (tmp->tm_isdst > 1)
1350		tmp->tm_isdst = 1;
1351	t = time2(tmp, funcp, offset, &okay);
1352#ifdef PCTS
1353	/*
1354	** PCTS code courtesy Grant Sullivan (grant@osf.org).
1355	*/
1356	if (okay)
1357		return t;
1358	if (tmp->tm_isdst < 0)
1359		tmp->tm_isdst = 0;	/* reset to std and try again */
1360#endif /* defined PCTS */
1361#ifndef PCTS
1362	if (okay || tmp->tm_isdst < 0)
1363		return t;
1364#endif /* !defined PCTS */
1365	/*
1366	** We're supposed to assume that somebody took a time of one type
1367	** and did some math on it that yielded a "struct tm" that's bad.
1368	** We try to divine the type they started from and adjust to the
1369	** type they need.
1370	*/
1371	/*
1372	** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
1373	*/
1374	sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
1375		lclptr : gmtptr);
1376#ifdef ALL_STATE
1377	if (sp == NULL)
1378		return WRONG;
1379#endif /* defined ALL_STATE */
1380	for (samei = 0; samei < sp->typecnt; ++samei) {
1381		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1382			continue;
1383		for (otheri = 0; otheri < sp->typecnt; ++otheri) {
1384			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1385				continue;
1386			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1387					sp->ttis[samei].tt_gmtoff;
1388			tmp->tm_isdst = !tmp->tm_isdst;
1389			t = time2(tmp, funcp, offset, &okay);
1390			if (okay)
1391				return t;
1392			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1393					sp->ttis[samei].tt_gmtoff;
1394			tmp->tm_isdst = !tmp->tm_isdst;
1395		}
1396	}
1397	return WRONG;
1398}
1399
1400time_t
1401mktime(tmp)
1402struct tm * const	tmp;
1403{
1404	return time1(tmp, localsub, 0L);
1405}
1406
1407#ifdef STD_INSPIRED
1408
1409time_t
1410timelocal(tmp)
1411struct tm * const	tmp;
1412{
1413	tmp->tm_isdst = -1;	/* in case it wasn't initialized */
1414	return mktime(tmp);
1415}
1416
1417time_t
1418timegm(tmp)
1419struct tm * const	tmp;
1420{
1421	tmp->tm_isdst = 0;
1422	return time1(tmp, gmtsub, 0L);
1423}
1424
1425time_t
1426timeoff(tmp, offset)
1427struct tm * const	tmp;
1428const long		offset;
1429{
1430	tmp->tm_isdst = 0;
1431	return time1(tmp, gmtsub, offset);
1432}
1433
1434#endif /* defined STD_INSPIRED */
1435
1436#ifdef CMUCS
1437
1438/*
1439** The following is supplied for compatibility with
1440** previous versions of the CMUCS runtime library.
1441*/
1442
1443long
1444gtime(tmp)
1445struct tm * const	tmp;
1446{
1447	const time_t	t = mktime(tmp);
1448
1449	if (t == WRONG)
1450		return -1;
1451	return t;
1452}
1453
1454#endif /* defined CMUCS */
1455
1456/*
1457** XXX--is the below the right way to conditionalize??
1458*/
1459
1460#ifdef STD_INSPIRED
1461
1462/*
1463** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
1464** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
1465** is not the case if we are accounting for leap seconds.
1466** So, we provide the following conversion routines for use
1467** when exchanging timestamps with POSIX conforming systems.
1468*/
1469
1470static long
1471leapcorr(timep)
1472time_t *	timep;
1473{
1474	register struct state *		sp;
1475	register struct lsinfo *	lp;
1476	register int			i;
1477
1478	if (!lcl_is_set)
1479		(void) tzset();
1480	sp = lclptr;
1481	i = sp->leapcnt;
1482	while (--i >= 0) {
1483		lp = &sp->lsis[i];
1484		if (*timep >= lp->ls_trans)
1485			return lp->ls_corr;
1486	}
1487	return 0;
1488}
1489
1490time_t
1491time2posix(t)
1492time_t	t;
1493{
1494	return t - leapcorr(&t);
1495}
1496
1497time_t
1498posix2time(t)
1499time_t	t;
1500{
1501	time_t	x;
1502	time_t	y;
1503
1504	/*
1505	** For a positive leap second hit, the result
1506	** is not unique.  For a negative leap second
1507	** hit, the corresponding time doesn't exist,
1508	** so we return an adjacent second.
1509	*/
1510	x = t + leapcorr(&t);
1511	y = x - leapcorr(&x);
1512	if (y < t) {
1513		do {
1514			x++;
1515			y = x - leapcorr(&x);
1516		} while (y < t);
1517		if (t != y)
1518			return x - 1;
1519	} else if (y > t) {
1520		do {
1521			--x;
1522			y = x - leapcorr(&x);
1523		} while (y > t);
1524		if (t != y)
1525			return x + 1;
1526	}
1527	return x;
1528}
1529
1530#endif /* defined STD_INSPIRED */
1531