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