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