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