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