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