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