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