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