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