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