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