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