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