xref: /original-bsd/lib/libc/gen/ctime.c (revision 76321dfe)
1 /*
2  * Copyright (c) 1987, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Arthur David Olson of the National Cancer Institute.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #if defined(LIBC_SCCS) && !defined(lint)
12 static char sccsid[] = "@(#)ctime.c	8.2 (Berkeley) 03/20/94";
13 #endif /* LIBC_SCCS and not lint */
14 
15 /*
16 ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
17 ** POSIX-style TZ environment variable handling from Guy Harris
18 ** (guy@auspex.com).
19 */
20 
21 /*LINTLIBRARY*/
22 
23 #include <sys/param.h>
24 #include <fcntl.h>
25 #include <time.h>
26 #include <tzfile.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 
32 #ifdef __STDC__
33 #include <stdlib.h>
34 
35 #define P(s)		s
36 #define alloc_size_t	size_t
37 #define qsort_size_t	size_t
38 #define fread_size_t	size_t
39 #define fwrite_size_t	size_t
40 
41 #else /* !defined __STDC__ */
42 
43 #define P(s)		()
44 
45 typedef char *		genericptr_t;
46 typedef unsigned	alloc_size_t;
47 typedef int		qsort_size_t;
48 typedef int		fread_size_t;
49 typedef int		fwrite_size_t;
50 
51 extern char *	calloc();
52 extern char *	malloc();
53 extern char *	realloc();
54 extern char *	getenv();
55 
56 #endif /* !defined __STDC__ */
57 
58 extern time_t	time();
59 
60 #define ACCESS_MODE	O_RDONLY
61 #define OPEN_MODE	O_RDONLY
62 
63 #ifndef WILDABBR
64 /*
65 ** Someone might make incorrect use of a time zone abbreviation:
66 **	1.	They might reference tzname[0] before calling tzset (explicitly
67 **	 	or implicitly).
68 **	2.	They might reference tzname[1] before calling tzset (explicitly
69 **	 	or implicitly).
70 **	3.	They might reference tzname[1] after setting to a time zone
71 **		in which Daylight Saving Time is never observed.
72 **	4.	They might reference tzname[0] after setting to a time zone
73 **		in which Standard Time is never observed.
74 **	5.	They might reference tm.TM_ZONE after calling offtime.
75 ** What's best to do in the above cases is open to debate;
76 ** for now, we just set things up so that in any of the five cases
77 ** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
78 ** string "tzname[0] used before set", and similarly for the other cases.
79 ** And another:  initialize tzname[0] to "ERA", with an explanation in the
80 ** manual page of what this "time zone abbreviation" means (doing this so
81 ** that tzname[0] has the "normal" length of three characters).
82 */
83 #define WILDABBR	"   "
84 #endif /* !defined WILDABBR */
85 
86 #ifndef TRUE
87 #define TRUE		1
88 #define FALSE		0
89 #endif /* !defined TRUE */
90 
91 static const char GMT[] = "GMT";
92 
93 struct ttinfo {				/* time type information */
94 	long		tt_gmtoff;	/* GMT offset in seconds */
95 	int		tt_isdst;	/* used to set tm_isdst */
96 	int		tt_abbrind;	/* abbreviation list index */
97 	int		tt_ttisstd;	/* TRUE if transition is std time */
98 };
99 
100 struct lsinfo {				/* leap second information */
101 	time_t		ls_trans;	/* transition time */
102 	long		ls_corr;	/* correction to apply */
103 };
104 
105 struct state {
106 	int		leapcnt;
107 	int		timecnt;
108 	int		typecnt;
109 	int		charcnt;
110 	time_t		ats[TZ_MAX_TIMES];
111 	unsigned char	types[TZ_MAX_TIMES];
112 	struct ttinfo	ttis[TZ_MAX_TYPES];
113 	char		chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ?
114 				TZ_MAX_CHARS + 1 : sizeof GMT];
115 	struct lsinfo	lsis[TZ_MAX_LEAPS];
116 };
117 
118 struct rule {
119 	int		r_type;		/* type of rule--see below */
120 	int		r_day;		/* day number of rule */
121 	int		r_week;		/* week number of rule */
122 	int		r_mon;		/* month number of rule */
123 	long		r_time;		/* transition time of rule */
124 };
125 
126 #define	JULIAN_DAY		0	/* Jn - Julian day */
127 #define	DAY_OF_YEAR		1	/* n - day of year */
128 #define	MONTH_NTH_DAY_OF_WEEK	2	/* Mm.n.d - month, week, day of week */
129 
130 /*
131 ** Prototypes for static functions.
132 */
133 
134 static long		detzcode P((const char * codep));
135 static const char *	getzname P((const char * strp));
136 static const char *	getnum P((const char * strp, int * nump, int min,
137 				int max));
138 static const char *	getsecs P((const char * strp, long * secsp));
139 static const char *	getoffset P((const char * strp, long * offsetp));
140 static const char *	getrule P((const char * strp, struct rule * rulep));
141 static void		gmtload P((struct state * sp));
142 static void		gmtsub P((const time_t * timep, long offset,
143 				struct tm * tmp));
144 static void		localsub P((const time_t * timep, long offset,
145 				struct tm * tmp));
146 static void		normalize P((int * tensptr, int * unitsptr, int base));
147 static void		settzname P((void));
148 static time_t		time1 P((struct tm * tmp, void (* funcp)(),
149 				long offset));
150 static time_t		time2 P((struct tm *tmp, void (* funcp)(),
151 				long offset, int * okayp));
152 static void		timesub P((const time_t * timep, long offset,
153 				const struct state * sp, struct tm * tmp));
154 static int		tmcomp P((const struct tm * atmp,
155 				const struct tm * btmp));
156 static time_t		transtime P((time_t janfirst, int year,
157 				const struct rule * rulep, long offset));
158 static int		tzload P((const char * name, struct state * sp));
159 static int		tzparse P((const char * name, struct state * sp,
160 				int lastditch));
161 
162 #ifdef ALL_STATE
163 static struct state *	lclptr;
164 static struct state *	gmtptr;
165 #endif /* defined ALL_STATE */
166 
167 #ifndef ALL_STATE
168 static struct state	lclmem;
169 static struct state	gmtmem;
170 #define lclptr		(&lclmem)
171 #define gmtptr		(&gmtmem)
172 #endif /* State Farm */
173 
174 static int		lcl_is_set;
175 static int		gmt_is_set;
176 
177 char *			tzname[2] = {
178 	WILDABBR,
179 	WILDABBR
180 };
181 
182 #ifdef USG_COMPAT
183 time_t			timezone = 0;
184 int			daylight = 0;
185 #endif /* defined USG_COMPAT */
186 
187 #ifdef ALTZONE
188 time_t			altzone = 0;
189 #endif /* defined ALTZONE */
190 
191 static long
192 detzcode(codep)
193 const char * const	codep;
194 {
195 	register long	result;
196 	register int	i;
197 
198 	result = 0;
199 	for (i = 0; i < 4; ++i)
200 		result = (result << 8) | (codep[i] & 0xff);
201 	return result;
202 }
203 
204 static void
205 settzname()
206 {
207 	register const struct state * const	sp = lclptr;
208 	register int				i;
209 
210 	tzname[0] = WILDABBR;
211 	tzname[1] = WILDABBR;
212 #ifdef USG_COMPAT
213 	daylight = 0;
214 	timezone = 0;
215 #endif /* defined USG_COMPAT */
216 #ifdef ALTZONE
217 	altzone = 0;
218 #endif /* defined ALTZONE */
219 #ifdef ALL_STATE
220 	if (sp == NULL) {
221 		tzname[0] = tzname[1] = GMT;
222 		return;
223 	}
224 #endif /* defined ALL_STATE */
225 	for (i = 0; i < sp->typecnt; ++i) {
226 		register const struct ttinfo * const	ttisp = &sp->ttis[i];
227 
228 		tzname[ttisp->tt_isdst] =
229 			(char *) &sp->chars[ttisp->tt_abbrind];
230 #ifdef USG_COMPAT
231 		if (ttisp->tt_isdst)
232 			daylight = 1;
233 		if (i == 0 || !ttisp->tt_isdst)
234 			timezone = -(ttisp->tt_gmtoff);
235 #endif /* defined USG_COMPAT */
236 #ifdef ALTZONE
237 		if (i == 0 || ttisp->tt_isdst)
238 			altzone = -(ttisp->tt_gmtoff);
239 #endif /* defined ALTZONE */
240 	}
241 	/*
242 	** And to get the latest zone names into tzname. . .
243 	*/
244 	for (i = 0; i < sp->timecnt; ++i) {
245 		register const struct ttinfo * const	ttisp =
246 							&sp->ttis[sp->types[i]];
247 
248 		tzname[ttisp->tt_isdst] =
249 			(char *) &sp->chars[ttisp->tt_abbrind];
250 	}
251 }
252 
253 static int
254 tzload(name, sp)
255 register const char *		name;
256 register struct state * const	sp;
257 {
258 	register const char *	p;
259 	register int		i;
260 	register int		fid;
261 
262 	if (name == NULL && (name = TZDEFAULT) == NULL)
263 		return -1;
264 	{
265 		char		fullname[FILENAME_MAX + 1];
266 
267 		if (name[0] == ':')
268 			++name;
269 		if (name[0] != '/') {
270 			if ((p = TZDIR) == NULL)
271 				return -1;
272 			if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
273 				return -1;
274 			(void) strcpy(fullname, p);
275 			(void) strcat(fullname, "/");
276 			(void) strcat(fullname, name);
277 			name = fullname;
278 		}
279 		if ((fid = open(name, OPEN_MODE)) == -1)
280 			return -1;
281 	}
282 	{
283 		register const struct tzhead *	tzhp;
284 		char				buf[sizeof *sp + sizeof *tzhp];
285 		int				ttisstdcnt;
286 
287 		i = read(fid, buf, sizeof buf);
288 		if (close(fid) != 0 || i < sizeof *tzhp)
289 			return -1;
290 		tzhp = (struct tzhead *) buf;
291 		ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
292 		sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
293 		sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
294 		sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
295 		sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
296 		if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
297 			sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
298 			sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
299 			sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
300 			(ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
301 				return -1;
302 		if (i < sizeof *tzhp +
303 			sp->timecnt * (4 + sizeof (char)) +
304 			sp->typecnt * (4 + 2 * sizeof (char)) +
305 			sp->charcnt * sizeof (char) +
306 			sp->leapcnt * 2 * 4 +
307 			ttisstdcnt * sizeof (char))
308 				return -1;
309 		p = buf + sizeof *tzhp;
310 		for (i = 0; i < sp->timecnt; ++i) {
311 			sp->ats[i] = detzcode(p);
312 			p += 4;
313 		}
314 		for (i = 0; i < sp->timecnt; ++i) {
315 			sp->types[i] = (unsigned char) *p++;
316 			if (sp->types[i] >= sp->typecnt)
317 				return -1;
318 		}
319 		for (i = 0; i < sp->typecnt; ++i) {
320 			register struct ttinfo *	ttisp;
321 
322 			ttisp = &sp->ttis[i];
323 			ttisp->tt_gmtoff = detzcode(p);
324 			p += 4;
325 			ttisp->tt_isdst = (unsigned char) *p++;
326 			if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
327 				return -1;
328 			ttisp->tt_abbrind = (unsigned char) *p++;
329 			if (ttisp->tt_abbrind < 0 ||
330 				ttisp->tt_abbrind > sp->charcnt)
331 					return -1;
332 		}
333 		for (i = 0; i < sp->charcnt; ++i)
334 			sp->chars[i] = *p++;
335 		sp->chars[i] = '\0';	/* ensure '\0' at end */
336 		for (i = 0; i < sp->leapcnt; ++i) {
337 			register struct lsinfo *	lsisp;
338 
339 			lsisp = &sp->lsis[i];
340 			lsisp->ls_trans = detzcode(p);
341 			p += 4;
342 			lsisp->ls_corr = detzcode(p);
343 			p += 4;
344 		}
345 		for (i = 0; i < sp->typecnt; ++i) {
346 			register struct ttinfo *	ttisp;
347 
348 			ttisp = &sp->ttis[i];
349 			if (ttisstdcnt == 0)
350 				ttisp->tt_ttisstd = FALSE;
351 			else {
352 				ttisp->tt_ttisstd = *p++;
353 				if (ttisp->tt_ttisstd != TRUE &&
354 					ttisp->tt_ttisstd != FALSE)
355 						return -1;
356 			}
357 		}
358 	}
359 	return 0;
360 }
361 
362 static const int	mon_lengths[2][MONSPERYEAR] = {
363 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
364 	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
365 };
366 
367 static const int	year_lengths[2] = {
368 	DAYSPERNYEAR, DAYSPERLYEAR
369 };
370 
371 /*
372 ** Given a pointer into a time zone string, scan until a character that is not
373 ** a valid character in a zone name is found.  Return a pointer to that
374 ** character.
375 */
376 
377 static const char *
378 getzname(strp)
379 register const char *	strp;
380 {
381 	register char	c;
382 
383 	while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
384 		c != '+')
385 			++strp;
386 	return strp;
387 }
388 
389 /*
390 ** Given a pointer into a time zone string, extract a number from that string.
391 ** Check that the number is within a specified range; if it is not, return
392 ** NULL.
393 ** Otherwise, return a pointer to the first character not part of the number.
394 */
395 
396 static const char *
397 getnum(strp, nump, min, max)
398 register const char *	strp;
399 int * const		nump;
400 const int		min;
401 const int		max;
402 {
403 	register char	c;
404 	register int	num;
405 
406 	if (strp == NULL || !isdigit(*strp))
407 		return NULL;
408 	num = 0;
409 	while ((c = *strp) != '\0' && isdigit(c)) {
410 		num = num * 10 + (c - '0');
411 		if (num > max)
412 			return NULL;	/* illegal value */
413 		++strp;
414 	}
415 	if (num < min)
416 		return NULL;		/* illegal value */
417 	*nump = num;
418 	return strp;
419 }
420 
421 /*
422 ** Given a pointer into a time zone string, extract a number of seconds,
423 ** in hh[:mm[:ss]] form, from the string.
424 ** If any error occurs, return NULL.
425 ** Otherwise, return a pointer to the first character not part of the number
426 ** of seconds.
427 */
428 
429 static const char *
430 getsecs(strp, secsp)
431 register const char *	strp;
432 long * const		secsp;
433 {
434 	int	num;
435 
436 	strp = getnum(strp, &num, 0, HOURSPERDAY);
437 	if (strp == NULL)
438 		return NULL;
439 	*secsp = num * SECSPERHOUR;
440 	if (*strp == ':') {
441 		++strp;
442 		strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
443 		if (strp == NULL)
444 			return NULL;
445 		*secsp += num * SECSPERMIN;
446 		if (*strp == ':') {
447 			++strp;
448 			strp = getnum(strp, &num, 0, SECSPERMIN - 1);
449 			if (strp == NULL)
450 				return NULL;
451 			*secsp += num;
452 		}
453 	}
454 	return strp;
455 }
456 
457 /*
458 ** Given a pointer into a time zone string, extract an offset, in
459 ** [+-]hh[:mm[:ss]] form, from the string.
460 ** If any error occurs, return NULL.
461 ** Otherwise, return a pointer to the first character not part of the time.
462 */
463 
464 static const char *
465 getoffset(strp, offsetp)
466 register const char *	strp;
467 long * const		offsetp;
468 {
469 	register int	neg;
470 
471 	if (*strp == '-') {
472 		neg = 1;
473 		++strp;
474 	} else if (isdigit(*strp) || *strp++ == '+')
475 		neg = 0;
476 	else	return NULL;		/* illegal offset */
477 	strp = getsecs(strp, offsetp);
478 	if (strp == NULL)
479 		return NULL;		/* illegal time */
480 	if (neg)
481 		*offsetp = -*offsetp;
482 	return strp;
483 }
484 
485 /*
486 ** Given a pointer into a time zone string, extract a rule in the form
487 ** date[/time].  See POSIX section 8 for the format of "date" and "time".
488 ** If a valid rule is not found, return NULL.
489 ** Otherwise, return a pointer to the first character not part of the rule.
490 */
491 
492 static const char *
493 getrule(strp, rulep)
494 const char *			strp;
495 register struct rule * const	rulep;
496 {
497 	if (*strp == 'J') {
498 		/*
499 		** Julian day.
500 		*/
501 		rulep->r_type = JULIAN_DAY;
502 		++strp;
503 		strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
504 	} else if (*strp == 'M') {
505 		/*
506 		** Month, week, day.
507 		*/
508 		rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
509 		++strp;
510 		strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
511 		if (strp == NULL)
512 			return NULL;
513 		if (*strp++ != '.')
514 			return NULL;
515 		strp = getnum(strp, &rulep->r_week, 1, 5);
516 		if (strp == NULL)
517 			return NULL;
518 		if (*strp++ != '.')
519 			return NULL;
520 		strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
521 	} else if (isdigit(*strp)) {
522 		/*
523 		** Day of year.
524 		*/
525 		rulep->r_type = DAY_OF_YEAR;
526 		strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
527 	} else	return NULL;		/* invalid format */
528 	if (strp == NULL)
529 		return NULL;
530 	if (*strp == '/') {
531 		/*
532 		** Time specified.
533 		*/
534 		++strp;
535 		strp = getsecs(strp, &rulep->r_time);
536 	} else	rulep->r_time = 2 * SECSPERHOUR;	/* default = 2:00:00 */
537 	return strp;
538 }
539 
540 /*
541 ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
542 ** year, a rule, and the offset from GMT at the time that rule takes effect,
543 ** calculate the Epoch-relative time that rule takes effect.
544 */
545 
546 static time_t
547 transtime(janfirst, year, rulep, offset)
548 const time_t				janfirst;
549 const int				year;
550 register const struct rule * const	rulep;
551 const long				offset;
552 {
553 	register int	leapyear;
554 	register time_t	value;
555 	register int	i;
556 	int		d, m1, yy0, yy1, yy2, dow;
557 
558 	leapyear = isleap(year);
559 	switch (rulep->r_type) {
560 
561 	case JULIAN_DAY:
562 		/*
563 		** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
564 		** years.
565 		** In non-leap years, or if the day number is 59 or less, just
566 		** add SECSPERDAY times the day number-1 to the time of
567 		** January 1, midnight, to get the day.
568 		*/
569 		value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
570 		if (leapyear && rulep->r_day >= 60)
571 			value += SECSPERDAY;
572 		break;
573 
574 	case DAY_OF_YEAR:
575 		/*
576 		** n - day of year.
577 		** Just add SECSPERDAY times the day number to the time of
578 		** January 1, midnight, to get the day.
579 		*/
580 		value = janfirst + rulep->r_day * SECSPERDAY;
581 		break;
582 
583 	case MONTH_NTH_DAY_OF_WEEK:
584 		/*
585 		** Mm.n.d - nth "dth day" of month m.
586 		*/
587 		value = janfirst;
588 		for (i = 0; i < rulep->r_mon - 1; ++i)
589 			value += mon_lengths[leapyear][i] * SECSPERDAY;
590 
591 		/*
592 		** Use Zeller's Congruence to get day-of-week of first day of
593 		** month.
594 		*/
595 		m1 = (rulep->r_mon + 9) % 12 + 1;
596 		yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
597 		yy1 = yy0 / 100;
598 		yy2 = yy0 % 100;
599 		dow = ((26 * m1 - 2) / 10 +
600 			1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
601 		if (dow < 0)
602 			dow += DAYSPERWEEK;
603 
604 		/*
605 		** "dow" is the day-of-week of the first day of the month.  Get
606 		** the day-of-month (zero-origin) of the first "dow" day of the
607 		** month.
608 		*/
609 		d = rulep->r_day - dow;
610 		if (d < 0)
611 			d += DAYSPERWEEK;
612 		for (i = 1; i < rulep->r_week; ++i) {
613 			if (d + DAYSPERWEEK >=
614 				mon_lengths[leapyear][rulep->r_mon - 1])
615 					break;
616 			d += DAYSPERWEEK;
617 		}
618 
619 		/*
620 		** "d" is the day-of-month (zero-origin) of the day we want.
621 		*/
622 		value += d * SECSPERDAY;
623 		break;
624 	}
625 
626 	/*
627 	** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
628 	** question.  To get the Epoch-relative time of the specified local
629 	** time on that day, add the transition time and the current offset
630 	** from GMT.
631 	*/
632 	return value + rulep->r_time + offset;
633 }
634 
635 /*
636 ** Given a POSIX section 8-style TZ string, fill in the rule tables as
637 ** appropriate.
638 */
639 
640 static int
641 tzparse(name, sp, lastditch)
642 const char *			name;
643 register struct state * const	sp;
644 const int			lastditch;
645 {
646 	const char *			stdname;
647 	const char *			dstname;
648 	int				stdlen;
649 	int				dstlen;
650 	long				stdoffset;
651 	long				dstoffset;
652 	register time_t *		atp;
653 	register unsigned char *	typep;
654 	register char *			cp;
655 	register int			load_result;
656 
657 	stdname = name;
658 	if (lastditch) {
659 		stdlen = strlen(name);	/* length of standard zone name */
660 		name += stdlen;
661 		if (stdlen >= sizeof sp->chars)
662 			stdlen = (sizeof sp->chars) - 1;
663 	} else {
664 		name = getzname(name);
665 		stdlen = name - stdname;
666 		if (stdlen < 3)
667 			return -1;
668 	}
669 	if (*name == '\0')
670 		return -1;
671 	else {
672 		name = getoffset(name, &stdoffset);
673 		if (name == NULL)
674 			return -1;
675 	}
676 	load_result = tzload(TZDEFRULES, sp);
677 	if (load_result != 0)
678 		sp->leapcnt = 0;		/* so, we're off a little */
679 	if (*name != '\0') {
680 		dstname = name;
681 		name = getzname(name);
682 		dstlen = name - dstname;	/* length of DST zone name */
683 		if (dstlen < 3)
684 			return -1;
685 		if (*name != '\0' && *name != ',' && *name != ';') {
686 			name = getoffset(name, &dstoffset);
687 			if (name == NULL)
688 				return -1;
689 		} else	dstoffset = stdoffset - SECSPERHOUR;
690 		if (*name == ',' || *name == ';') {
691 			struct rule	start;
692 			struct rule	end;
693 			register int	year;
694 			register time_t	janfirst;
695 			time_t		starttime;
696 			time_t		endtime;
697 
698 			++name;
699 			if ((name = getrule(name, &start)) == NULL)
700 				return -1;
701 			if (*name++ != ',')
702 				return -1;
703 			if ((name = getrule(name, &end)) == NULL)
704 				return -1;
705 			if (*name != '\0')
706 				return -1;
707 			sp->typecnt = 2;	/* standard time and DST */
708 			/*
709 			** Two transitions per year, from EPOCH_YEAR to 2037.
710 			*/
711 			sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
712 			if (sp->timecnt > TZ_MAX_TIMES)
713 				return -1;
714 			sp->ttis[0].tt_gmtoff = -dstoffset;
715 			sp->ttis[0].tt_isdst = 1;
716 			sp->ttis[0].tt_abbrind = stdlen + 1;
717 			sp->ttis[1].tt_gmtoff = -stdoffset;
718 			sp->ttis[1].tt_isdst = 0;
719 			sp->ttis[1].tt_abbrind = 0;
720 			atp = sp->ats;
721 			typep = sp->types;
722 			janfirst = 0;
723 			for (year = EPOCH_YEAR; year <= 2037; ++year) {
724 				starttime = transtime(janfirst, year, &start,
725 					stdoffset);
726 				endtime = transtime(janfirst, year, &end,
727 					dstoffset);
728 				if (starttime > endtime) {
729 					*atp++ = endtime;
730 					*typep++ = 1;	/* DST ends */
731 					*atp++ = starttime;
732 					*typep++ = 0;	/* DST begins */
733 				} else {
734 					*atp++ = starttime;
735 					*typep++ = 0;	/* DST begins */
736 					*atp++ = endtime;
737 					*typep++ = 1;	/* DST ends */
738 				}
739 				janfirst +=
740 					year_lengths[isleap(year)] * SECSPERDAY;
741 			}
742 		} else {
743 			int		sawstd;
744 			int		sawdst;
745 			long		stdfix;
746 			long		dstfix;
747 			long		oldfix;
748 			int		isdst;
749 			register int	i;
750 
751 			if (*name != '\0')
752 				return -1;
753 			if (load_result != 0)
754 				return -1;
755 			/*
756 			** Compute the difference between the real and
757 			** prototype standard and summer time offsets
758 			** from GMT, and put the real standard and summer
759 			** time offsets into the rules in place of the
760 			** prototype offsets.
761 			*/
762 			sawstd = FALSE;
763 			sawdst = FALSE;
764 			stdfix = 0;
765 			dstfix = 0;
766 			for (i = 0; i < sp->typecnt; ++i) {
767 				if (sp->ttis[i].tt_isdst) {
768 					oldfix = dstfix;
769 					dstfix =
770 					    sp->ttis[i].tt_gmtoff + dstoffset;
771 					if (sawdst && (oldfix != dstfix))
772 						return -1;
773 					sp->ttis[i].tt_gmtoff = -dstoffset;
774 					sp->ttis[i].tt_abbrind = stdlen + 1;
775 					sawdst = TRUE;
776 				} else {
777 					oldfix = stdfix;
778 					stdfix =
779 					    sp->ttis[i].tt_gmtoff + stdoffset;
780 					if (sawstd && (oldfix != stdfix))
781 						return -1;
782 					sp->ttis[i].tt_gmtoff = -stdoffset;
783 					sp->ttis[i].tt_abbrind = 0;
784 					sawstd = TRUE;
785 				}
786 			}
787 			/*
788 			** Make sure we have both standard and summer time.
789 			*/
790 			if (!sawdst || !sawstd)
791 				return -1;
792 			/*
793 			** Now correct the transition times by shifting
794 			** them by the difference between the real and
795 			** prototype offsets.  Note that this difference
796 			** can be different in standard and summer time;
797 			** the prototype probably has a 1-hour difference
798 			** between standard and summer time, but a different
799 			** difference can be specified in TZ.
800 			*/
801 			isdst = FALSE;	/* we start in standard time */
802 			for (i = 0; i < sp->timecnt; ++i) {
803 				register const struct ttinfo *	ttisp;
804 
805 				/*
806 				** If summer time is in effect, and the
807 				** transition time was not specified as
808 				** standard time, add the summer time
809 				** offset to the transition time;
810 				** otherwise, add the standard time offset
811 				** to the transition time.
812 				*/
813 				ttisp = &sp->ttis[sp->types[i]];
814 				sp->ats[i] +=
815 					(isdst && !ttisp->tt_ttisstd) ?
816 						dstfix : stdfix;
817 				isdst = ttisp->tt_isdst;
818 			}
819 		}
820 	} else {
821 		dstlen = 0;
822 		sp->typecnt = 1;		/* only standard time */
823 		sp->timecnt = 0;
824 		sp->ttis[0].tt_gmtoff = -stdoffset;
825 		sp->ttis[0].tt_isdst = 0;
826 		sp->ttis[0].tt_abbrind = 0;
827 	}
828 	sp->charcnt = stdlen + 1;
829 	if (dstlen != 0)
830 		sp->charcnt += dstlen + 1;
831 	if (sp->charcnt > sizeof sp->chars)
832 		return -1;
833 	cp = sp->chars;
834 	(void) strncpy(cp, stdname, stdlen);
835 	cp += stdlen;
836 	*cp++ = '\0';
837 	if (dstlen != 0) {
838 		(void) strncpy(cp, dstname, dstlen);
839 		*(cp + dstlen) = '\0';
840 	}
841 	return 0;
842 }
843 
844 static void
845 gmtload(sp)
846 struct state * const	sp;
847 {
848 	if (tzload(GMT, sp) != 0)
849 		(void) tzparse(GMT, sp, TRUE);
850 }
851 
852 void
853 tzset()
854 {
855 	register const char *	name;
856 	void tzsetwall();
857 
858 	name = getenv("TZ");
859 	if (name == NULL) {
860 		tzsetwall();
861 		return;
862 	}
863 	lcl_is_set = TRUE;
864 #ifdef ALL_STATE
865 	if (lclptr == NULL) {
866 		lclptr = (struct state *) malloc(sizeof *lclptr);
867 		if (lclptr == NULL) {
868 			settzname();	/* all we can do */
869 			return;
870 		}
871 	}
872 #endif /* defined ALL_STATE */
873 	if (*name == '\0') {
874 		/*
875 		** User wants it fast rather than right.
876 		*/
877 		lclptr->leapcnt = 0;		/* so, we're off a little */
878 		lclptr->timecnt = 0;
879 		lclptr->ttis[0].tt_gmtoff = 0;
880 		lclptr->ttis[0].tt_abbrind = 0;
881 		(void) strcpy(lclptr->chars, GMT);
882 	} else if (tzload(name, lclptr) != 0)
883 		if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
884 			(void) gmtload(lclptr);
885 	settzname();
886 }
887 
888 void
889 tzsetwall()
890 {
891 	lcl_is_set = TRUE;
892 #ifdef ALL_STATE
893 	if (lclptr == NULL) {
894 		lclptr = (struct state *) malloc(sizeof *lclptr);
895 		if (lclptr == NULL) {
896 			settzname();	/* all we can do */
897 			return;
898 		}
899 	}
900 #endif /* defined ALL_STATE */
901 	if (tzload((char *) NULL, lclptr) != 0)
902 		gmtload(lclptr);
903 	settzname();
904 }
905 
906 /*
907 ** The easy way to behave "as if no library function calls" localtime
908 ** is to not call it--so we drop its guts into "localsub", which can be
909 ** freely called.  (And no, the PANS doesn't require the above behavior--
910 ** but it *is* desirable.)
911 **
912 ** The unused offset argument is for the benefit of mktime variants.
913 */
914 
915 /*ARGSUSED*/
916 static void
917 localsub(timep, offset, tmp)
918 const time_t * const	timep;
919 const long		offset;
920 struct tm * const	tmp;
921 {
922 	register struct state *	sp;
923 	register const struct ttinfo *	ttisp;
924 	register int			i;
925 	const time_t			t = *timep;
926 
927 	if (!lcl_is_set)
928 		tzset();
929 	sp = lclptr;
930 #ifdef ALL_STATE
931 	if (sp == NULL) {
932 		gmtsub(timep, offset, tmp);
933 		return;
934 	}
935 #endif /* defined ALL_STATE */
936 	if (sp->timecnt == 0 || t < sp->ats[0]) {
937 		i = 0;
938 		while (sp->ttis[i].tt_isdst)
939 			if (++i >= sp->typecnt) {
940 				i = 0;
941 				break;
942 			}
943 	} else {
944 		for (i = 1; i < sp->timecnt; ++i)
945 			if (t < sp->ats[i])
946 				break;
947 		i = sp->types[i - 1];
948 	}
949 	ttisp = &sp->ttis[i];
950 	/*
951 	** To get (wrong) behavior that's compatible with System V Release 2.0
952 	** you'd replace the statement below with
953 	**	t += ttisp->tt_gmtoff;
954 	**	timesub(&t, 0L, sp, tmp);
955 	*/
956 	timesub(&t, ttisp->tt_gmtoff, sp, tmp);
957 	tmp->tm_isdst = ttisp->tt_isdst;
958 	tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
959 	tmp->tm_zone = &sp->chars[ttisp->tt_abbrind];
960 }
961 
962 struct tm *
963 localtime(timep)
964 const time_t * const	timep;
965 {
966 	static struct tm	tm;
967 
968 	localsub(timep, 0L, &tm);
969 	return &tm;
970 }
971 
972 /*
973 ** gmtsub is to gmtime as localsub is to localtime.
974 */
975 
976 static void
977 gmtsub(timep, offset, tmp)
978 const time_t * const	timep;
979 const long		offset;
980 struct tm * const	tmp;
981 {
982 	if (!gmt_is_set) {
983 		gmt_is_set = TRUE;
984 #ifdef ALL_STATE
985 		gmtptr = (struct state *) malloc(sizeof *gmtptr);
986 		if (gmtptr != NULL)
987 #endif /* defined ALL_STATE */
988 			gmtload(gmtptr);
989 	}
990 	timesub(timep, offset, gmtptr, tmp);
991 	/*
992 	** Could get fancy here and deliver something such as
993 	** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
994 	** but this is no time for a treasure hunt.
995 	*/
996 	if (offset != 0)
997 		tmp->tm_zone = WILDABBR;
998 	else {
999 #ifdef ALL_STATE
1000 		if (gmtptr == NULL)
1001 			tmp->TM_ZONE = GMT;
1002 		else	tmp->TM_ZONE = gmtptr->chars;
1003 #endif /* defined ALL_STATE */
1004 #ifndef ALL_STATE
1005 		tmp->tm_zone = gmtptr->chars;
1006 #endif /* State Farm */
1007 	}
1008 }
1009 
1010 struct tm *
1011 gmtime(timep)
1012 const time_t * const	timep;
1013 {
1014 	static struct tm	tm;
1015 
1016 	gmtsub(timep, 0L, &tm);
1017 	return &tm;
1018 }
1019 
1020 static void
1021 timesub(timep, offset, sp, tmp)
1022 const time_t * const			timep;
1023 const long				offset;
1024 register const struct state * const	sp;
1025 register struct tm * const		tmp;
1026 {
1027 	register const struct lsinfo *	lp;
1028 	register long			days;
1029 	register long			rem;
1030 	register int			y;
1031 	register int			yleap;
1032 	register const int *		ip;
1033 	register long			corr;
1034 	register int			hit;
1035 	register int			i;
1036 
1037 	corr = 0;
1038 	hit = FALSE;
1039 #ifdef ALL_STATE
1040 	i = (sp == NULL) ? 0 : sp->leapcnt;
1041 #endif /* defined ALL_STATE */
1042 #ifndef ALL_STATE
1043 	i = sp->leapcnt;
1044 #endif /* State Farm */
1045 	while (--i >= 0) {
1046 		lp = &sp->lsis[i];
1047 		if (*timep >= lp->ls_trans) {
1048 			if (*timep == lp->ls_trans)
1049 				hit = ((i == 0 && lp->ls_corr > 0) ||
1050 					lp->ls_corr > sp->lsis[i - 1].ls_corr);
1051 			corr = lp->ls_corr;
1052 			break;
1053 		}
1054 	}
1055 	days = *timep / SECSPERDAY;
1056 	rem = *timep % SECSPERDAY;
1057 #ifdef mc68k
1058 	if (*timep == 0x80000000) {
1059 		/*
1060 		** A 3B1 muffs the division on the most negative number.
1061 		*/
1062 		days = -24855;
1063 		rem = -11648;
1064 	}
1065 #endif /* mc68k */
1066 	rem += (offset - corr);
1067 	while (rem < 0) {
1068 		rem += SECSPERDAY;
1069 		--days;
1070 	}
1071 	while (rem >= SECSPERDAY) {
1072 		rem -= SECSPERDAY;
1073 		++days;
1074 	}
1075 	tmp->tm_hour = (int) (rem / SECSPERHOUR);
1076 	rem = rem % SECSPERHOUR;
1077 	tmp->tm_min = (int) (rem / SECSPERMIN);
1078 	tmp->tm_sec = (int) (rem % SECSPERMIN);
1079 	if (hit)
1080 		/*
1081 		** A positive leap second requires a special
1082 		** representation.  This uses "... ??:59:60".
1083 		*/
1084 		++(tmp->tm_sec);
1085 	tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
1086 	if (tmp->tm_wday < 0)
1087 		tmp->tm_wday += DAYSPERWEEK;
1088 	y = EPOCH_YEAR;
1089 	if (days >= 0)
1090 		for ( ; ; ) {
1091 			yleap = isleap(y);
1092 			if (days < (long) year_lengths[yleap])
1093 				break;
1094 			++y;
1095 			days = days - (long) year_lengths[yleap];
1096 		}
1097 	else do {
1098 		--y;
1099 		yleap = isleap(y);
1100 		days = days + (long) year_lengths[yleap];
1101 	} while (days < 0);
1102 	tmp->tm_year = y - TM_YEAR_BASE;
1103 	tmp->tm_yday = (int) days;
1104 	ip = mon_lengths[yleap];
1105 	for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
1106 		days = days - (long) ip[tmp->tm_mon];
1107 	tmp->tm_mday = (int) (days + 1);
1108 	tmp->tm_isdst = 0;
1109 	tmp->tm_gmtoff = offset;
1110 }
1111 
1112 /*
1113 ** A la X3J11
1114 */
1115 
1116 char *
1117 asctime(timeptr)
1118 register const struct tm *	timeptr;
1119 {
1120 	static const char	wday_name[DAYSPERWEEK][3] = {
1121 		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1122 	};
1123 	static const char	mon_name[MONSPERYEAR][3] = {
1124 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
1125 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1126 	};
1127 	static char	result[26];
1128 
1129 	(void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n",
1130 		wday_name[timeptr->tm_wday],
1131 		mon_name[timeptr->tm_mon],
1132 		timeptr->tm_mday, timeptr->tm_hour,
1133 		timeptr->tm_min, timeptr->tm_sec,
1134 		TM_YEAR_BASE + timeptr->tm_year);
1135 	return result;
1136 }
1137 
1138 char *
1139 ctime(timep)
1140 const time_t * const	timep;
1141 {
1142 	return asctime(localtime(timep));
1143 }
1144 
1145 /*
1146 ** Adapted from code provided by Robert Elz, who writes:
1147 **	The "best" way to do mktime I think is based on an idea of Bob
1148 **	Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
1149 **	It does a binary search of the time_t space.  Since time_t's are
1150 **	just 32 bits, its a max of 32 iterations (even at 64 bits it
1151 **	would still be very reasonable).
1152 */
1153 
1154 #ifndef WRONG
1155 #define WRONG	(-1)
1156 #endif /* !defined WRONG */
1157 
1158 static void
1159 normalize(tensptr, unitsptr, base)
1160 int * const	tensptr;
1161 int * const	unitsptr;
1162 const int	base;
1163 {
1164 	if (*unitsptr >= base) {
1165 		*tensptr += *unitsptr / base;
1166 		*unitsptr %= base;
1167 	} else if (*unitsptr < 0) {
1168 		*tensptr -= 1 + (-(*unitsptr + 1)) / base;
1169 		*unitsptr = base - 1 - (-(*unitsptr + 1)) % base;
1170 	}
1171 }
1172 
1173 static int
1174 tmcomp(atmp, btmp)
1175 register const struct tm * const atmp;
1176 register const struct tm * const btmp;
1177 {
1178 	register int	result;
1179 
1180 	if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
1181 		(result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1182 		(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1183 		(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1184 		(result = (atmp->tm_min - btmp->tm_min)) == 0)
1185 			result = atmp->tm_sec - btmp->tm_sec;
1186 	return result;
1187 }
1188 
1189 static time_t
1190 time2(tmp, funcp, offset, okayp)
1191 struct tm * const	tmp;
1192 void (* const		funcp)();
1193 const long		offset;
1194 int * const		okayp;
1195 {
1196 	register const struct state *	sp;
1197 	register int			dir;
1198 	register int			bits;
1199 	register int			i, j ;
1200 	register int			saved_seconds;
1201 	time_t				newt;
1202 	time_t				t;
1203 	struct tm			yourtm, mytm;
1204 
1205 	*okayp = FALSE;
1206 	yourtm = *tmp;
1207 	if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
1208 		normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
1209 	normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
1210 	normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
1211 	normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
1212 	while (yourtm.tm_mday <= 0) {
1213 		--yourtm.tm_year;
1214 		yourtm.tm_mday +=
1215 			year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
1216 	}
1217 	while (yourtm.tm_mday > DAYSPERLYEAR) {
1218 		yourtm.tm_mday -=
1219 		    year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
1220 		++yourtm.tm_year;
1221 	}
1222 	for ( ; ; ) {
1223 		i = mon_lengths[isleap(yourtm.tm_year +
1224 			TM_YEAR_BASE)][yourtm.tm_mon];
1225 		if (yourtm.tm_mday <= i)
1226 			break;
1227 		yourtm.tm_mday -= i;
1228 		if (++yourtm.tm_mon >= MONSPERYEAR) {
1229 			yourtm.tm_mon = 0;
1230 			++yourtm.tm_year;
1231 		}
1232 	}
1233 	saved_seconds = yourtm.tm_sec;
1234 	yourtm.tm_sec = 0;
1235 	/*
1236 	** Calculate the number of magnitude bits in a time_t
1237 	** (this works regardless of whether time_t is
1238 	** signed or unsigned, though lint complains if unsigned).
1239 	*/
1240 	for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
1241 		;
1242 	/*
1243 	** If time_t is signed, then 0 is the median value,
1244 	** if time_t is unsigned, then 1 << bits is median.
1245 	*/
1246 	t = (t < 0) ? 0 : ((time_t) 1 << bits);
1247 	for ( ; ; ) {
1248 		(*funcp)(&t, offset, &mytm);
1249 		dir = tmcomp(&mytm, &yourtm);
1250 		if (dir != 0) {
1251 			if (bits-- < 0)
1252 				return WRONG;
1253 			if (bits < 0)
1254 				--t;
1255 			else if (dir > 0)
1256 				t -= (time_t) 1 << bits;
1257 			else	t += (time_t) 1 << bits;
1258 			continue;
1259 		}
1260 		if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
1261 			break;
1262 		/*
1263 		** Right time, wrong type.
1264 		** Hunt for right time, right type.
1265 		** It's okay to guess wrong since the guess
1266 		** gets checked.
1267 		*/
1268 		sp = (const struct state *)
1269 			((funcp == localsub) ? lclptr : gmtptr);
1270 #ifdef ALL_STATE
1271 		if (sp == NULL)
1272 			return WRONG;
1273 #endif /* defined ALL_STATE */
1274 		for (i = 0; i < sp->typecnt; ++i) {
1275 			if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
1276 				continue;
1277 			for (j = 0; j < sp->typecnt; ++j) {
1278 				if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
1279 					continue;
1280 				newt = t + sp->ttis[j].tt_gmtoff -
1281 					sp->ttis[i].tt_gmtoff;
1282 				(*funcp)(&newt, offset, &mytm);
1283 				if (tmcomp(&mytm, &yourtm) != 0)
1284 					continue;
1285 				if (mytm.tm_isdst != yourtm.tm_isdst)
1286 					continue;
1287 				/*
1288 				** We have a match.
1289 				*/
1290 				t = newt;
1291 				goto label;
1292 			}
1293 		}
1294 		return WRONG;
1295 	}
1296 label:
1297 	t += saved_seconds;
1298 	(*funcp)(&t, offset, tmp);
1299 	*okayp = TRUE;
1300 	return t;
1301 }
1302 
1303 static time_t
1304 time1(tmp, funcp, offset)
1305 struct tm * const	tmp;
1306 void (* const		funcp)();
1307 const long		offset;
1308 {
1309 	register time_t			t;
1310 	register const struct state *	sp;
1311 	register int			samei, otheri;
1312 	int				okay;
1313 
1314 	if (tmp->tm_isdst > 1)
1315 		tmp->tm_isdst = 1;
1316 	t = time2(tmp, funcp, offset, &okay);
1317 	if (okay || tmp->tm_isdst < 0)
1318 		return t;
1319 	/*
1320 	** We're supposed to assume that somebody took a time of one type
1321 	** and did some math on it that yielded a "struct tm" that's bad.
1322 	** We try to divine the type they started from and adjust to the
1323 	** type they need.
1324 	*/
1325 	sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
1326 #ifdef ALL_STATE
1327 	if (sp == NULL)
1328 		return WRONG;
1329 #endif /* defined ALL_STATE */
1330 	for (samei = 0; samei < sp->typecnt; ++samei) {
1331 		if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
1332 			continue;
1333 		for (otheri = 0; otheri < sp->typecnt; ++otheri) {
1334 			if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
1335 				continue;
1336 			tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
1337 					sp->ttis[samei].tt_gmtoff;
1338 			tmp->tm_isdst = !tmp->tm_isdst;
1339 			t = time2(tmp, funcp, offset, &okay);
1340 			if (okay)
1341 				return t;
1342 			tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
1343 					sp->ttis[samei].tt_gmtoff;
1344 			tmp->tm_isdst = !tmp->tm_isdst;
1345 		}
1346 	}
1347 	return WRONG;
1348 }
1349 
1350 time_t
1351 mktime(tmp)
1352 struct tm * const	tmp;
1353 {
1354 	return time1(tmp, localsub, 0L);
1355 }
1356