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