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