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