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